pax_global_header00006660000000000000000000000064144331470160014515gustar00rootroot0000000000000052 comment=849072ef827b4abab754253e1e63e7b410a31084 open-telemetry-opentelemetry-go-contrib-2135499/000077500000000000000000000000001443314701600216235ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/.gitattributes000066400000000000000000000001311443314701600245110ustar00rootroot00000000000000* text=auto eol=lf *.{cmd,[cC][mM][dD]} text eol=crlf *.{bat,[bB][aA][tT]} text eol=crlf open-telemetry-opentelemetry-go-contrib-2135499/.github/000077500000000000000000000000001443314701600231635ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/.github/ISSUE_TEMPLATE/000077500000000000000000000000001443314701600253465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/.github/ISSUE_TEMPLATE/bug_report_instrgen.md000066400000000000000000000011301443314701600317440ustar00rootroot00000000000000--- name: '[instrgen] Bug report' about: Create a report of invalid behavior about the instrgen package to help us improve title: '' labels: 'bug, area: instrgen' assignees: '@open-telemetry/go-instrumentation-approvers' --- ### Description A clear and concise description of what the bug is. ### Environment - OS: [e.g. iOS] - Architecture: [e.g. x86, i386] - Go Version: [e.g. 1.15] - `instrgen` version: [e.g. v0.14.0, 3c7face] ### Steps To Reproduce 1. Using this code ... 2. Run ... 3. See error ... ### Expected behavior A clear and concise description of what you expected to happen. open-telemetry-opentelemetry-go-contrib-2135499/.github/ISSUE_TEMPLATE/feature_request_instrgen.md000066400000000000000000000014011443314701600330000ustar00rootroot00000000000000--- name: '[instrgen] Feature request' about: Suggest an idea for the instrgen package title: '' labels: enhancement labels: 'enhancement, area: instrgen' assignees: '@open-telemetry/go-instrumentation-approvers' --- ### Problem Statement A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] ### Proposed Solution A clear and concise description of what you want to happen. #### Alternatives A clear and concise description of any alternative solutions or features you've considered. #### Prior Art A clear and concise list of any similar and existing solutions from other projects that provide context to possible solutions. ### Additional Context Add any other context or screenshots about the feature request here. open-telemetry-opentelemetry-go-contrib-2135499/.github/ISSUE_TEMPLATE/instrumentation-request.md000066400000000000000000000035301443314701600326220ustar00rootroot00000000000000--- name: Instrumentation Request about: Suggest instrumentation to include in this project title: Request to Add Instrumentation for labels: 'enhancement, area: instrumentation' assignees: '' --- ## Background **Package Link**: ### Why can this instrumentation not be included in the package itself? ### Why can this instrumentation not be hosted in a dedicated repository? ## Proposed Solution ### Tracing - attributes: - - events: - - links: - ### Metrics Instruments - : - type: - unit: - description: - attributes: - ### Prior Art - ## Tasks - Code complete: - [ ] Comprehensive unit tests. - [ ] End-to-end integration tests. - [ ] Tests all passing. - [ ] Instrumentation functionality verified. - Documented - [ ] Added to the [OpenTelemetry Registry](https://opentelemetry.io/registry/) - [ ] README included for the module describing high-level purpose. - [ ] Complete documentation of all public API including package documentation. - [ ] [Instrumentation documentation](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/instrumentation/README.md#instrumentation-packages) updated. - Examples - [ ] `Dockerfile` file to build example application. - [ ] `docker-compose.yml` to run example in a docker environment to demonstrate instrumentation. open-telemetry-opentelemetry-go-contrib-2135499/.github/codecov.yaml000066400000000000000000000004071443314701600254720ustar00rootroot00000000000000codecov: require_ci_to_pass: yes coverage: precision: 1 round: down range: "70...100" status: project: default: target: auto threshold: 1% comment: layout: "reach,diff,flags,tree" behavior: default require_changes: yes open-telemetry-opentelemetry-go-contrib-2135499/.github/dependabot.yml000066400000000000000000000451401443314701600260170ustar00rootroot00000000000000# File generated by dbotconf; DO NOT EDIT. version: 2 updates: - package-ecosystem: github-actions directory: / labels: - dependencies - actions - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/Shopify/sarama/otelsarama/example/consumer labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/Shopify/sarama/otelsarama/example/producer labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/astaxie/beego/otelbeego/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/aws/aws-lambda-go/otellambda/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/emicklei/go-restful/otelrestful/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/gin-gonic/gin/otelgin/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/go-kit/kit/otelkit/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/gorilla/mux/otelmux/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/github.com/labstack/echo/otelecho/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/gopkg.in/macaron.v1/otelmacaron/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/net/http/httptrace/otelhttptrace/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: docker directory: /instrumentation/net/http/otelhttp/example labels: - dependencies - docker - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: / labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /detectors/aws/ec2 labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /detectors/aws/ecs labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /detectors/aws/eks labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /detectors/aws/lambda labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /detectors/gcp labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrgen labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrgen/driver labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrgen/driver/testdata/interface labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/Shopify/sarama/otelsarama labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/Shopify/sarama/otelsarama/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/Shopify/sarama/otelsarama/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/astaxie/beego/otelbeego labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/astaxie/beego/otelbeego/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/astaxie/beego/otelbeego/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-lambda-go/otellambda labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-lambda-go/otellambda/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-lambda-go/otellambda/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-sdk-go-v2/otelaws labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/emicklei/go-restful/otelrestful labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/emicklei/go-restful/otelrestful/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/emicklei/go-restful/otelrestful/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gin-gonic/gin/otelgin labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gin-gonic/gin/otelgin/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gin-gonic/gin/otelgin/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/go-kit/kit/otelkit labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/go-kit/kit/otelkit/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/go-kit/kit/otelkit/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gocql/gocql/otelgocql labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gocql/gocql/otelgocql/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gocql/gocql/otelgocql/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gorilla/mux/otelmux labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gorilla/mux/otelmux/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/gorilla/mux/otelmux/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/labstack/echo/otelecho labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/labstack/echo/otelecho/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/github.com/labstack/echo/otelecho/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/google.golang.org/grpc/otelgrpc labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/google.golang.org/grpc/otelgrpc/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/google.golang.org/grpc/otelgrpc/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/gopkg.in/macaron.v1/otelmacaron labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/gopkg.in/macaron.v1/otelmacaron/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/gopkg.in/macaron.v1/otelmacaron/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/host labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/host/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/httptrace/otelhttptrace labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/httptrace/otelhttptrace/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/httptrace/otelhttptrace/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/otelhttp labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/otelhttp/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/net/http/otelhttp/test labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/runtime labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /instrumentation/runtime/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/autoprop labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/aws labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/b3 labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/jaeger labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/opencensus labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/opencensus/examples labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /propagators/ot labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /samplers/aws/xray labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /samplers/jaegerremote labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /samplers/jaegerremote/example labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /samplers/probability/consistent labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /tools labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday - package-ecosystem: gomod directory: /zpages labels: - dependencies - go - Skip Changelog schedule: interval: weekly day: sunday open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/000077500000000000000000000000001443314701600252205ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/changelog.yml000066400000000000000000000025641443314701600277010ustar00rootroot00000000000000# This action requires that any PR targeting the main branch should touch at # least one CHANGELOG file. If a CHANGELOG entry is not required, or if # performing maintance on the Changelog, add either \"[chore]\" to the title of # the pull request or add the \"Skip Changelog\" label to disable this action. name: changelog on: pull_request: types: [opened, synchronize, reopened, labeled, unlabeled] branches: - main jobs: changelog: runs-on: ubuntu-latest if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependencies') && !contains(github.event.pull_request.labels.*.name, 'Skip Changelog') && !contains(github.event.pull_request.title, '[chore]')}} steps: - uses: actions/checkout@v3 - name: Check for CHANGELOG changes run: | # Only the latest commit of the feature branch is available # automatically. To diff with the base branch, we need to # fetch that too (and we only need its latest commit). git fetch origin ${{ github.base_ref }} --depth=1 if [[ $(git diff --name-only FETCH_HEAD | grep CHANGELOG) ]] then echo "A CHANGELOG was modified. Looks good!" else echo "No CHANGELOG was modified." echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." false fi open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/ci.yml000066400000000000000000000153211443314701600263400ustar00rootroot00000000000000name: build_and_test on: push: branches: - main pull_request: env: # path to where test results will be saved TEST_RESULTS: /tmp/test-results # Default version of Go to use by CI workflows. This should be the latest # release of Go; developers likely use the latest release in development and # we want to catch any bugs (e.g. lint errors, race detection) with this # release before they are merged. The Go compatibility guarantees ensure # backwards compatibility with the previous two minor releases and we # explicitly test our code for these versions so keeping this at prior # versions does not add value. DEFAULT_GO_VERSION: "1.20" jobs: lint: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 - name: Setup Environment run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: Module cache uses: actions/cache@v3 env: cache-name: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} - name: Tools cache uses: actions/cache@v3 env: cache-name: go-tools-cache with: path: ~/.tools key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('./internal/tools/**') }} - name: Generate run: make generate - name: Run linters run: make dependabot-check license-check lint vanity-import-check - name: Build run: make build - name: Check clean repository run: make check-clean-work-tree test-race: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 - name: Setup Environment run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: Module cache uses: actions/cache@v3 env: cache-name: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} - name: Run tests with race detector run: make test-race test-coverage: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 - name: Setup Environment run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: Module cache uses: actions/cache@v3 env: cache-name: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} - name: Run coverage tests run: | make test-coverage mkdir $TEST_RESULTS cp coverage.out $TEST_RESULTS cp coverage.txt $TEST_RESULTS cp coverage.html $TEST_RESULTS - name: Upload coverage report uses: codecov/codecov-action@v3.1.4 with: file: ./coverage.txt fail_ci_if_error: true verbose: true - name: Store coverage test output uses: actions/upload-artifact@v3 with: name: opentelemetry-go-contrib-test-output path: ${{ env.TEST_RESULTS }} compatibility-test: strategy: matrix: go-version: ["1.20", 1.19] os: [ubuntu-latest, macos-latest, windows-latest] # GitHub Actions does not support arm* architectures on default # runners. It is possible to acomplish this with a self-hosted runner # if we want to add this in the future: # https://docs.github.com/en/actions/hosting-your-own-runners/using-self-hosted-runners-in-a-workflow arch: ["386", amd64] exclude: # Not a supported Go OS/architecture. - os: macos-latest arch: "386" runs-on: ${{ matrix.os }} steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v3 - name: Setup Environment run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH shell: bash - name: Module cache uses: actions/cache@v3 env: cache-name: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} - name: Run tests env: GOARCH: ${{ matrix.arch }} run: make test-short test-compatibility: runs-on: ubuntu-latest needs: [compatibility-test] steps: - name: Test if compatibility-test workflow passed run: | echo ${{ needs.compatibility-test.result }} test ${{ needs.compatibility-test.result }} == "success" integration: strategy: matrix: target: [test-gocql, test-mongo-driver, test-gomemcache] runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup Environment run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: Module cache uses: actions/cache@v3 env: cache-name: go-mod-cache with: path: ~/go/pkg/mod key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/go.sum') }} - name: Run coverage tests ${{ matrix.target }} env: INTEGRATION: ${{ matrix.target }} run: | make ${{ matrix.target }} mkdir -p $TEST_RESULTS find . -name 'coverage.html' > "${TEST_RESULTS}/coverage.lst" tar -n -cf - -T "${TEST_RESULTS}/coverage.lst" | tar -C "${TEST_RESULTS}" -xvf - - name: Upload coverage report uses: codecov/codecov-action@v3.1.4 if: hashFiles('coverage.out') != '' with: file: ./coverage.out fail_ci_if_error: true verbose: true - name: Store coverage test output uses: actions/upload-artifact@v3 with: name: opentelemetry-go-contrib-test-output path: ${{ env.TEST_RESULTS }} test-integration: runs-on: ubuntu-latest needs: [integration] steps: - name: Test if integration workflow passed run: | echo ${{ needs.integration.result }} test ${{ needs.integration.result }} == "success" open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/codeql_analysis.yml000066400000000000000000000020721443314701600311160ustar00rootroot00000000000000on: workflow_dispatch: schedule: # ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) # │ │ ┌───────────── day of the month (1 - 31) # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) # │ │ │ │ │ # │ │ │ │ │ # │ │ │ │ │ # * * * * * - cron: '30 1 * * *' jobs: CodeQL-Build: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: go - name: Autobuild uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/create-dependabot-pr.yml000066400000000000000000000007671443314701600317420ustar00rootroot00000000000000name: dependabot-pr on: workflow_dispatch: jobs: create-pr: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v4 with: go-version: '1.20' - uses: actions/checkout@v3 - name: Install zsh run: sudo apt-get update; sudo apt-get install zsh - name: Run dependabot-pr.sh run: ./.github/workflows/scripts/dependabot-pr.sh env: GITHUB_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }} open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/dependabot.yml000066400000000000000000000013731443314701600300540ustar00rootroot00000000000000name: Dependabot-Tidier on: pull_request: types: [ labeled ] jobs: mod_tidier: if: ${{ contains(github.event.pull_request.labels.*.name, 'dependencies') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} - uses: actions/setup-go@v4 with: go-version: '^1.20.0' - uses: evantorrie/mott-the-tidier@v1-beta id: modtidy with: gomods: '**/go.mod' gomodsum_only: true - uses: stefanzweifel/git-auto-commit-action@v4 id: autocommit with: commit_message: Auto-fix go.sum changes in dependent modules - name: changes run: | echo "Changes detected: ${{ steps.autocommit.outputs.changes_detected }}" open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/gosec.yml000066400000000000000000000016121443314701600270430ustar00rootroot00000000000000name: Run Gosec on: workflow_dispatch: schedule: # ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) # │ │ ┌───────────── day of the month (1 - 31) # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) # │ │ │ │ │ # │ │ │ │ │ # │ │ │ │ │ # * * * * * - cron: '30 2 * * *' jobs: tests: runs-on: ubuntu-latest env: GO111MODULE: on steps: - name: Checkout Source uses: actions/checkout@v3 - name: Run Gosec Security Scanner uses: securego/gosec@master with: args: ./... open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/scripts/000077500000000000000000000000001443314701600267075ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/.github/workflows/scripts/dependabot-pr.sh000077500000000000000000000034371443314701600320010ustar00rootroot00000000000000#!/bin/zsh -ex # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. git config user.name opentelemetrybot git config user.email 107717825+opentelemetrybot@users.noreply.github.com PR_NAME=dependabot-prs/`date +'%Y-%m-%dT%H%M%S'` git checkout -b $PR_NAME IFS=$'\n' requests=($( gh pr list --search "author:app/dependabot" -l "go" --json title --jq '.[].title' )) message="" dirs=(`find . -type f -name "go.mod" -exec dirname {} \; | sort | egrep '^./'`) declare -A mods for line in $requests; do echo $line if [[ $line != build\(deps\)* ]]; then continue fi module=$(echo $line | cut -f 3 -d " ") if [[ $module == go.opentelemetry.io/contrib* ]]; then continue fi version=$(echo $line | cut -f 7 -d " ") mods[$module]=$version message+=$line message+=$'\n' done for module version in ${(kv)mods}; do topdir=`pwd` for dir in $dirs; do echo "checking $dir" cd $dir && if grep -q "$module " go.mod; then go get "$module"@v"$version"; fi cd $topdir done done make go-mod-tidy make build git add go.sum go.mod git add "**/go.sum" "**/go.mod" git commit -m "dependabot updates `date` $message" git push origin $PR_NAME gh pr create --title "[chore] dependabot updates `date`" --body "$message" open-telemetry-opentelemetry-go-contrib-2135499/.gitignore000066400000000000000000000004251443314701600236140ustar00rootroot00000000000000.DS_Store Thumbs.db .tools/ .idea/ .vscode/ *.iml *.so coverage.* go.work go.work.sum example instrumentation/google.golang.org/grpc/otelgrpc/example/server/server instrumentation/google.golang.org/grpc/otelgrpc/example/client/client instrgen/driver/testdata/**/*.go_pass_* open-telemetry-opentelemetry-go-contrib-2135499/.golangci.yml000066400000000000000000000223301443314701600242070ustar00rootroot00000000000000# See https://github.com/golangci/golangci-lint#config-file run: issues-exit-code: 1 #Default tests: true #Default timeout: 2m linters: # Disable everything by default so upgrades to not include new "default # enabled" linters. disable-all: true # Specifically enable linters we want to use. enable: - depguard - errcheck - godot - gofmt - goimports - gosimple - govet - ineffassign - misspell - revive - staticcheck - typecheck - unused issues: # Maximum issues count per one linter. # Set to 0 to disable. # Default: 50 # Setting to unlimited so the linter only is run once to debug all issues. max-issues-per-linter: 0 # Maximum count of issues with the same text. # Set to 0 to disable. # Default: 3 # Setting to unlimited so the linter only is run once to debug all issues. max-same-issues: 0 # Excluding configuration per-path, per-linter, per-text and per-source. exclude-rules: # TODO: Having appropriate comments for exported objects helps development, # even for objects in internal packages. Appropriate comments for all # exported objects should be added and this exclusion removed. - path: '.*internal/.*' text: "exported (method|function|type|const) (.+) should have comment or be unexported" linters: - revive # Yes, they are, but it's okay in a test. - path: _test\.go text: "exported func.*returns unexported type.*which can be annoying to use" linters: - revive # Example test functions should be treated like main. - path: example.*_test\.go text: "calls to (.+) only in main[(][)] or init[(][)] functions" linters: - revive include: # revive exported should have comment or be unexported. - EXC0012 # revive package comment should be of the form ... - EXC0013 linters-settings: depguard: # Check the list against standard lib. # Default: false include-go-root: true # A list of packages for the list type specified. # Default: [] packages: - "crypto/md5" - "crypto/sha1" - "crypto/**/pkix" ignore-file-rules: - "**/*_test.go" additional-guards: # Do not allow testing packages in non-test files. - list-type: denylist include-go-root: true packages: - testing - github.com/stretchr/testify ignore-file-rules: - "**/*_test.go" - "**/*test/*.go" - "**/internal/matchers/*.go" godot: exclude: # Exclude sentence fragments for lists. - '^[ ]*[-•]' # Exclude sentences prefixing a list. - ':$' goimports: local-prefixes: go.opentelemetry.io misspell: locale: US ignore-words: - cancelled revive: # Sets the default failure confidence. # This means that linting errors with less than 0.8 confidence will be ignored. # Default: 0.8 confidence: 0.01 rules: # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#blank-imports - name: blank-imports disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr - name: bool-literal-in-expr disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr - name: constant-logical-expr disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument # TODO (#2877) reenable linter when it is compatible. https://github.com/golangci/golangci-lint/issues/3280 - name: context-as-argument disabled: true arguments: allowTypesBefore: "*testing.T" # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type - name: context-keys-type disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit - name: deep-exit disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer - name: defer disabled: false arguments: - ["call-chain", "loop"] # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#dot-imports - name: dot-imports disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports - name: duplicated-imports disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return - name: early-return disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block - name: empty-block disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines - name: empty-lines disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming - name: error-naming disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return - name: error-return disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings - name: error-strings disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf - name: errorf disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported - name: exported disabled: false arguments: - "sayRepetitiveInsteadOfStutters" # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#flag-parameter - name: flag-parameter disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches - name: identical-branches disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return - name: if-return disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement - name: increment-decrement disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow - name: indent-error-flow disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing - name: import-shadowing disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments - name: package-comments disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range - name: range disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure - name: range-val-in-closure disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address - name: range-val-address disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id - name: redefines-builtin-id disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format - name: string-format disabled: false arguments: - - panic - '/^[^\n]*$/' - must not contain line breaks # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag - name: struct-tag disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else - name: superfluous-else disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal - name: time-equal disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming - name: var-naming disabled: false arguments: - ["ID"] # AllowList - ["Otel", "Aws", "Gcp"] # DenyList # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-declaration - name: var-declaration disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion - name: unconditional-recursion disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return - name: unexported-return disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error - name: unhandled-error disabled: false arguments: - "fmt.Fprint" - "fmt.Fprintf" - "fmt.Fprintln" - "fmt.Print" - "fmt.Printf" - "fmt.Println" # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unnecessary-stmt - name: unnecessary-stmt disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break - name: useless-break disabled: false # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value - name: waitgroup-by-value disabled: false open-telemetry-opentelemetry-go-contrib-2135499/CHANGELOG.md000066400000000000000000001144431443314701600234430ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068, #3108) ## [1.17.0/0.42.0/0.11.0] - 2023-05-23 ### Changed - Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#3822) ## [1.17.0-rc.1/0.42.0-rc.1/0.11.0-rc.1] - 2023-05-17 ### Changed - Upgrade dependencies of OpenTelemetry Go to use the new [`v1.16.0-rc.1`/`v0.39.0-rc.1` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.16.0-rc.1). - Remove `semver:` prefix from instrumentation version. (#3681, #3798) ### Deprecated - `SemVersion` functions in instrumentation packages are deprecated, use `Version` instead. (#3681, #3798) ## [1.16.1/0.41.1/0.10.1] - 2023-05-02 ### Added - The `WithPublicEndpoint` and `WithPublicEndpointFn` options in `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux`. (#3661) ### Changed - Upgrade dependencies of OpenTelemetry Go to use the new [`v1.15.1`/`v0.38.1` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.15.1) ### Fixed - AWS XRay Remote Sampling to preserve previous rule if updated rule property has not changed in `go.opentelemetry.io/contrib/samplers/aws/xray`. (#3619, #3620) ## [1.16.0/0.41.0/0.10.0] - 2023-04-28 ### Added - AWS SDK add `rpc.system` attribute in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#3582, #3617) ### Changed - Update `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` to align gRPC server span status with the changes in the OpenTelemetry specification. (#3685) - Adding the `db.statement` tag to spans in `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo` is now disabled by default. (#3519) ### Fixed - The error received by `otelecho` middleware is then passed back to upstream middleware instead of being swallowed. (#3656) - Prevent taking from reservoir in AWS XRay Remote Sampler when there is zero capacity in `go.opentelemetry.io/contrib/samplers/aws/xray`. (#3684) - Fix `otelhttp.Handler` in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` to propagate multiple `WriteHeader` calls while persisting the initial `statusCode`. (#3580) ## [1.16.0-rc.2/0.41.0-rc.2/0.10.0-rc.2] - 2023-03-23 ### Added - The `WithPublicEndpoint` and `WithPublicEndpointFn` options in `go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful`. (#3563) ### Fixed - AWS SDK rename attributes `aws.operation`, `aws.service` to `rpc.method`,`rpc.service` in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#3582, #3617) - AWS SDK span name to be of the format `Service.Operation` in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#3582, #3521) - Prevent sampler configuration reset from erroneously sampling first span in `go.opentelemetry.io/contrib/samplers/jaegerremote`. (#3603, #3604) ## [1.16.0-rc.1/0.41.0-rc.1/0.10.0-rc.1] - 2023-03-02 ### Changed - Dropped compatibility testing for [Go 1.18]. The project no longer guarantees support for this version of Go. (#3516) ## [1.15.0/0.40.0/0.9.0] - 2023-02-27 This release is the last to support [Go 1.18]. The next release will require at least [Go 1.19]. ### Added - Support [Go 1.20]. (#3372) - Add `SpanNameFormatter` option to package `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#3343) ### Changed - Change to use protobuf parser instead of encoding/json to accept enums as strings in `go.opentelemetry.io/contrib/samplers/jaegerremote`. (#3183) ### Fixed - Remove use of deprecated `"math/rand".Seed` in `go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example/producer`. (#3396) - Do not assume "aws" partition in ecs detector to prevent panic in `go.opentelemetry.io/contrib/detectors/aws/ecs`. (#3167) - The span name of producer spans from `go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama` is corrected to use `publish` instead of `send`. (#3369) - Attribute types are corrected in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#3369) - `aws.dynamodb.table_names` is now a string slice value. - `aws.dynamodb.global_secondary_indexes` is now a string slice value. - `aws.dynamodb.local_secondary_indexes` is now a string slice value. - `aws.dynamodb.attribute_definitions` is now a string slice value. - `aws.dynamodb.global_secondary_index_updates` is now a string slice value. - `aws.dynamodb.provisioned_read_capacity` is now a `float64` value. - `aws.dynamodb.provisioned_write_capacity` is now a `float64` value. ## [1.14.0/0.39.0/0.8.0] - 2023-02-07 ### Changed - Change `runtime.uptime` instrument in `go.opentelemetry.io/contrib/instrumentation/runtime` from `Int64ObservableUpDownCounter` to `Int64ObservableCounter`, since the value is monotonic. (#3347) - `samplers/jaegerremote`: change to use protobuf parser instead of encoding/json to accept enums as strings. (#3183) ### Fixed - The GCE detector in `go.opentelemetry.io/contrib/detectors/gcp` includes the "cloud.region" attribute when appropriate. (#3367) ## [1.13.0/0.38.0/0.7.0] - 2023-01-30 ### Added - Add `WithSpanNameFormatter` to `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` to allow customizing span names. (#3041) - Add missing recommended AWS Lambda resource attributes `faas.instance` and `faas.max_memory` in `go.opentelemetry.io/contrib/detectors/aws/lambda`. (#3148) - Improve documentation for `go.opentelemetry.io/contrib/samplers/jaegerremote` by providing examples of sampling endpoints. (#3147) - Add `WithServerName` to `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` to set the primary server name of a `Handler`. (#3182) ### Changed - Remove expensive calculation of uncompressed message size attribute in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#3168) - Upgrade all `semconv` packages to use `v1.17.0`. (#3182) - Upgrade dependencies of OpenTelemetry Go to use the new [`v1.12.0`/`v0.35.0` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.12.0). (#3190, #3170) ## [1.12.0/0.37.0/0.6.0] ### Added - Implemented retrieving the [`aws.ecs.*` resource attributes](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud_provider/aws/ecs/) in `go.opentelemetry.io/detectors/aws/ecs` based on the ECS Metadata v4 endpoint. (#2626) - The `WithLogger` option to `go.opentelemetry.io/contrib/samplers/jaegerremote` to allow users to pass a `logr.Logger` and have operations logged. (#2566) - Add the `messaging.url` & `messaging.system` attributes to all appropriate SQS operations in the `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws` package. (#2879) - Add example use of the metrics signal to `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/example`. (#2610) - [otelgin] Add support for filters to the `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin` package to provide the way to control which inbound requests are traced. (#2965, #2963) ### Fixed - Set the status_code span attribute even if the HTTP handler hasn't written anything. (#2822) - Do not wrap http.NoBody in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`, which fixes handling of that special request body. (#2983) ## [1.11.1/0.36.4/0.5.2] ### Added - Add trace context propagation support to `instrumentation/github.com/aws/aws-sdk-go-v2/otelaws` (#2856). - [otelgrpc] Add `WithMeterProvider` function to enable metric and add metric `rpc.server.duration` to otelgrpc instrumentation library. (#2700) ### Changed - Upgrade dependencies of OpenTelemetry Go to use the new [`v1.11.1`/`v0.33.0` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.11.1) ## [1.11.0/0.36.3/0.5.1] ### Changed - Upgrade dependencies of the OpenTelemetry Go Metric SDK to use the new [`v1.11.0`/`v0.32.3` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.11.0) ## [0.36.2] ### Changed - Upgrade dependencies of the OpenTelemetry Go Metric SDK to use the new [`v0.32.2` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk%2Fmetric%2Fv0.32.2) - Avoid getting a new Tracer for every RPC in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#2835) - Conditionally compute message size for tracing events using proto v2 API rather than legacy v1 API in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#2647) ### Deprecated - The `Inject` function in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` is deprecated. (#2838) - The `Extract` function in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` is deprecated. (#2838) ## [0.36.1] ### Changed - Upgrade dependencies of the OpenTelemetry Go Metric SDK to use the new [`v0.32.1` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk%2Fmetric%2Fv0.32.1) ### Removed - Drop support for Go 1.17. The project currently only supports Go 1.18 and above. (#2785) ## [0.36.0] ### Changed - Upgrade dependencies of the OpenTelemetry Go Metric SDK to use the new [`v0.32.0` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk%2Fmetric%2Fv0.32.0). (#2781, #2756, #2758, #2760, #2762) ## [1.10.0/0.35.0/0.5.0] ### Changed - Rename the `Typ` field of `"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc".InterceptorInfo` to `Type`. (#2688) - Use Go 1.19 as the default version for CI testing/linting. (#2675) ### Fixed - Fix the Jaeger propagator rejecting trace IDs that are both shorter than 128 bits and not exactly 64 bits long (while not being 0). Also fix the propagator rejecting span IDs shorter than 64 bits. This fixes compatibility with Jaeger clients encoding trace and span IDs as variable-length hex strings, [as required by the Jaeger propagation format](https://www.jaegertracing.io/docs/1.37/client-libraries/#value). (#2731) ## [1.9.0/0.34.0/0.4.0] - 2022-08-02 ### Added - Add gRPC trace `Filter` to the `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` package to provide the way to filter the traces automatically generated in interceptors. (#2572) - The `TextMapPropagator` function to `go.opentelemetry.io/contrib/propagators/autoprop`. This function is used to return a composite `TextMapPropagator` from registered names (instead of having to specify with an environment variable). (#2593) ### Changed - Upgraded all `semconv` package use to `v1.12.0`. (#2589) ## [1.8.0/0.33.0] - 2022-07-08 ### Added - The `go.opentelemetry.io/contrib/propagators/autoprop` package to provide configuration of propagators with useful defaults and envar support. (#2258) - `WithPublicEndpointFn` hook to dynamically detect public HTTP requests and set their trace parent as a link. (#2342) ### Fixed - Fix the `otelhttp`, `otelgin`, `otelmacaron`, `otelrestful` middlewares by using `SpanKindServer` when deciding the `SpanStatus`. This makes `4xx` response codes to not be an error anymore. (#2427) ## [1.7.0/0.32.0] - 2022-04-28 ### Added - Consistent probability sampler implementation. (#1379) ### Changed - Upgraded all `semconv` package use to `v1.10.0`. This includes a backwards incompatible change for the `otelgocql` package to conform with the specification [change](https://github.com/open-telemetry/opentelemetry-specification/pull/1973). The `db.cassandra.keyspace` attribute is now transmitted as the `db.name` attribute. (#2222) ### Fixed - Fix the `otelmux` middleware by using `SpanKindServer` when deciding the `SpanStatus`. This makes `4xx` response codes to not be an error anymore. (#1973) - Fixed jaegerremote sampler not behaving properly with per operation strategy set. (#2137) - Stopped injecting propagation context into response headers in otelhttp. (#2180) - Fix issue where attributes for DynamoDB were not added because of a string miss match. (#2272) ### Removed - Drop support for Go 1.16. The project currently only supports Go 1.17 and above. (#2314) ## [1.6.0/0.31.0] - 2022-03-28 ### Added - The project is now tested against Go 1.18 (in addition to the existing 1.16 and 1.17) (#1976) ### Changed - Upgraded all dependencies on stable modules from `go.opentelemetry.io/otel` from v1.5.0 to v1.6.1. (#2134) - Upgraded all dependencies on metric modules from `go.opentelemetry.io/otel` from v0.27.0 to v0.28.0. (#1977) ### Fixed - otelhttp: Avoid panic by adding nil check to `wrappedBody.Close` (#2164) ## [1.5.0/0.30.0/0.1.0] - 2022-03-16 ### Added - Added the `go.opentelemetry.io/contrib/samplers/jaegerremote` package. This package implements the Jaeger remote sampler for OpenTelemetry Go. (#936) - DynamoDB spans created with the `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws` package now have the appropriate database attributes added for the operation being performed. These attributes are detected automatically, but it is also now possible to provide a custom function to set attributes using `WithAttributeSetter`. (#1582) - Add resource detector for GCP cloud function. (#1584) - Add OpenTracing baggage extraction to the OpenTracing propagator in `go.opentelemetry.io/contrib/propagators/ot`. (#1880) ### Fixed - Fix the `echo` middleware by using `SpanKind.SERVER` when deciding the `SpanStatus`. This makes `4xx` response codes to not be an error anymore. (#1848) ### Removed - The deprecated `go.opentelemetry.io/contrib/exporters/metric/datadog` module is removed. (#1920) - The deprecated `go.opentelemetry.io/contrib/exporters/metric/dogstatsd` module is removed. (#1920) - The deprecated `go.opentelemetry.io/contrib/exporters/metric/cortex` module is removed. Use the `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` exporter as a replacement to send data to a collector which can then export with its PRW exporter. (#1920) ## [1.4.0/0.29.0] - 2022-02-14 ### Added - Add `WithClientTrace` option to `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`. (#875) ### Changed - All metric instruments from the `go.opentelemetry.io/contrib/instrumentation/runtime` package have been renamed from `runtime.go.*` to `process.runtime.go.*` so as to comply with OpenTelemetry semantic conventions. (#1549) ### Fixed - Change the `http-server-duration` instrument in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` to record milliseconds instead of microseconds. This changes fixes the code to comply with the OpenTelemetry specification. (#1414, #1537) - Fixed the region reported by the `"go.opentelemetry.io/contrib/detectors/gcp".CloudRun` detector to comply with the OpenTelemetry specification. It no longer includes the project scoped region path, instead just the region. (#1546) - The `"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp".Transport` type now correctly handles protocol switching responses. The returned response body implements the `io.ReadWriteCloser` interface if the underlying one does. This ensures that protocol switching requests receive a response body that they can write to. (#1329, #1628) ### Deprecated - The `go.opentelemetry.io/contrib/exporters/metric/datadog` module is deprecated. (#1639) - The `go.opentelemetry.io/contrib/exporters/metric/dogstatsd` module is deprecated. (#1639) - The `go.opentelemetry.io/contrib/exporters/metric/cortex` module is deprecated. Use the go.opentelemetry.io/otel/exporters/otlp/otlpmetric exporter as a replacement to send data to a collector which can then export with its PRW exporter. (#1639) ### Removed - Remove the `MinMaxSumCount` from cortex and datadog exporter. (#1554) - The `go.opentelemetry.io/contrib/exporters/metric/dogstatsd` exporter no longer support exporting histogram or exact data points. (#1639) - The `go.opentelemetry.io/contrib/exporters/metric/datadog` exporter no longer support exporting exact data points. (#1639) ## [1.3.0/0.28.0] - 2021-12-10 ### ⚠️ Notice ⚠️ We have updated the project minimum supported Go version to 1.16 ### Changed - `otelhttptrace.NewClientTrace` now uses `TracerProvider` from the parent context if one exists and none was set with `WithTracerProvider` (#874) ### Fixed - The `"go.opentelemetry.io/contrib/detector/aws/ecs".Detector` no longer errors if not running in ECS. (#1428) - `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` does not require instrumented HTTP handlers to call `Write` nor `WriteHeader` anymore. (#1443) ## [1.2.0/0.27.0] - 2021-11-15 ### Changed - Update dependency on the `go.opentelemetry.io/otel` project to `v1.2.0`. - `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig` updated to ensure access to the `TracerProvider`. - A `NewTracerProvider()` function is available to construct a recommended `TracerProvider` configuration. - `AllRecommendedOptions()` has been renamed to `WithRecommendedOptions()` and takes a `TracerProvider` as an argument. - `EventToCarrier()` and `Propagator()` are now `WithEventToCarrier()` and `WithPropagator()` to reflect that they return `Option` implementations. ## [1.1.1/0.26.1] - 2021-11-04 ### Changed - The `Transport`, `Handler`, and HTTP client convenience wrappers in the `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` package now use the `TracerProvider` from the parent context if one exists and none was explicitly set when configuring the instrumentation. (#873) - Semantic conventions now use `go.opentelemetry.io/otel/semconv/v1.7.0"`. (#1385) ## [1.1.0/0.26.0] - 2021-10-28 Update dependency on the `go.opentelemetry.io/otel` project to `v1.1.0`. ### Added - Add instrumentation for the `github.com/aws/aws-lambda-go` package. (#983) - Add resource detector for AWS Lambda. (#983) - Add `WithTracerProvider` option for `otelhttptrace.NewClientTrace`. (#1128) - Add optional AWS X-Ray configuration module for AWS Lambda Instrumentation. (#984) ### Fixed - The `go.opentelemetry.io/contrib/propagators/ot` propagator returns the words `true` or `false` for the `ot-tracer-sampled` header instead of numerical `0` and `1`. (#1358) ## [1.0.0/0.25.0] - 2021-10-06 - Resource detectors and propagators (with the exception of `go. opentelemetry.io/contrib/propagators/opencensus`) are now stable and released at v1.0.0. - Update dependency on the `go.opentelemetry.io/otel` project to `v1.0.1`. - Update dependency on `go.opentelemetry.io/otel/metric` to `v0.24.0`. ## [0.24.0] - 2021-09-21 - Update dependency on the `go.opentelemetry.io/otel` project to `v1.0.0`. ## [0.23.0] - 2021-09-08 ### Added - Add `WithoutSubSpans`, `WithRedactedHeaders`, `WithoutHeaders`, and `WithInsecureHeaders` options for `otelhttptrace.NewClientTrace`. (#879) ### Changed - Split `go.opentelemetry.io/contrib/propagators` module into `b3`, `jaeger`, `ot` modules. (#985) - `otelmongodb` span attributes, name and span status now conform to specification. (#769) - Migrated EC2 resource detector support from root module `go.opentelemetry.io/contrib/detectors/aws` to a separate EC2 resource detector module `go.opentelemetry.io/contrib/detectors/aws/ec2` (#1017) - Add `cloud.provider` and `cloud.platform` to AWS detectors. (#1043) - `otelhttptrace.NewClientTrace` now redacts known sensitive headers by default. (#879) ### Fixed - Fix span not marked as error in `otelhttp.Transport` when `RoundTrip` fails with an error. (#950) ## [0.22.0] - 2021-07-26 ### Added - Add the `zpages` span processor. (#894) ### Changed - The `b3.B3` type has been removed. `b3.New()` and `b3.WithInjectEncoding(encoding)` are added to replace it. (#868) ### Fixed - Fix deadlocks and race conditions in `otelsarama.WrapAsyncProducer`. The `messaging.message_id` and `messaging.kafka.partition` attributes are now not set if a message was not processed. (#754) (#755) (#881) - Fix `otelsarama.WrapAsyncProducer` so that the messages from the `Errors` channel contain the original `Metadata`. (#754) ## [0.21.0] - 2021-06-18 ### Fixed - Dockerfile based examples for `otelgin` and `otelmacaron`. (#767) ### Changed - Supported minimum version of Go bumped from 1.14 to 1.15. (#787) - EKS Resource Detector now use the Kubernetes Go client to obtain the ConfigMap. (#813) ### Removed - Remove service name from `otelmongodb` configuration and span attributes. (#763) ## [0.20.0] - 2021-04-23 ### Changed - The `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo` instrumentation now accepts a `WithCommandAttributeDisabled`, so the caller can specify whether to opt-out of tracing the mongo command. (#712) - Upgrade to v0.20.0 of `go.opentelemetry.io/otel`. (#758) - The B3 and Jaeger propagators now store their debug or deferred state in the context.Context instead of the SpanContext. (#758) ## [0.19.0] - 2021-03-19 ### Changed - Upgrade to v0.19.0 of `go.opentelemetry.io/otel`. - Fix Span names created in HTTP Instrumentation package to conform with guidelines. (#757) ## [0.18.0] - 2021-03-04 ### Fixed - `otelmemcache` no longer sets span status to OK instead of leaving it unset. (#477) - Fix goroutine leak in gRPC `StreamClientInterceptor`. (#581) ### Removed - Remove service name from `otelmemcache` configuration and span attributes. (#477) ## [0.17.0] - 2021-02-15 ### Added - Add `ot-tracer` propagator (#562) ### Changed - Rename project default branch from `master` to `main`. ### Fixed - Added failure message for AWS ECS resource detector for better debugging (#568) - Goroutine leak in gRPC StreamClientInterceptor while streamer returns an error. (#581) ## [0.16.0] - 2021-01-13 ### Fixed - Fix module path for AWS ECS resource detector (#517) ## [0.15.1] - 2020-12-14 ### Added - Add registry link check to `Makefile` and pre-release script. (#446) - A new AWS X-Ray ID Generator (#459) - Migrate CircleCI jobs to GitHub Actions (#476) - Add CodeQL GitHub Action (#506) - Add gosec workflow to GitHub Actions (#507) ### Fixed - Fixes the body replacement in otelhttp to not to mutate a nil body. (#484) ## [0.15.0] - 2020-12-11 ### Added - A new Amazon EKS resource detector. (#465) - A new `gcp.CloudRun` detector for detecting resource from a Cloud Run instance. (#455) ## [0.14.0] - 2020-11-20 ### Added - `otelhttp.{Get,Head,Post,PostForm}` convenience wrappers for their `http` counterparts. (#390) - The AWS detector now adds the cloud zone, host image ID, host type, and host name to the returned `Resource`. (#410) - Add Amazon ECS Resource Detector for AWS X-Ray. (#466) - Add propagator for AWS X-Ray (#462) ### Changed - Add semantic version to `Tracer` / `Meter` created by instrumentation packages `otelsaram`, `otelrestful`, `otelmongo`, `otelhttp` and `otelhttptrace`. (#412) - Update instrumentation guidelines about tracer / meter semantic version. (#412) - Replace internal tracer and meter helpers by helpers from `go.opentelemetry.io/otel`. (#414) - gRPC instrumentation sets span attribute `rpc.grpc.status_code`. (#453) ## Fixed - `/detectors/aws` no longer fails if instance metadata is not available (e.g. not running in AWS) (#401) - The AWS detector now returns a partial resource and an appropriate error if it encounters an error part way through determining a `Resource` identity. (#410) - The `host` instrumentation unit test has been updated to not depend on the system it runs on. (#426) ## [0.13.0] - 2020-10-09 ## Added - A Jaeger propagator. (#375) ## Changed - The `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` package instrumentation no longer accepts a `Tracer` as an argument to the interceptor function. Instead, a new `WithTracerProvider` option is added to configure the `TracerProvider` used when creating the `Tracer` for the instrumentation. (#373) - The `go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron` instrumentation now accepts a `TracerProvider` rather than a `Tracer`. (#374) - Remove `go.opentelemetry.io/otel/sdk` dependency from instrumentation. (#381) - Use `httpsnoop` in `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` to ensure `http.ResponseWriter` additional interfaces are preserved. (#388) ### Fixed - The `go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho.Middleware` no longer sends duplicate errors to the global `ErrorHandler`. (#377, #364) - The import comment in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` is now correctly quoted. (#379) - The B3 propagator sets the sample bitmask when the sampling decision is `debug`. (#369) ## [0.12.0] - 2020-09-25 ### Added - Benchmark tests for the gRPC instrumentation. (#296) - Integration testing for the gRPC instrumentation. (#297) - Allow custom labels to be added to net/http metrics. (#306) - Added B3 propagator, moving it out of open.telemetry.io/otel repo. (#344) ### Changed - Unify instrumentation about provider options for `go.mongodb.org/mongo-driver`, `gin-gonic/gin`, `gorilla/mux`, `labstack/echo`, `emicklei/go-restful`, `bradfitz/gomemcache`, `Shopify/sarama`, `net/http` and `beego`. (#303) - Update instrumentation guidelines about uniform provider options. Also, update style guide. (#303) - Make config struct of instrumentation unexported. (#303) - Instrumentations have been updated to adhere to the [configuration style guide's](https://github.com/open-telemetry/opentelemetry-go/blob/master/CONTRIBUTING.md#config) updated recommendation to use `newConfig()` instead of `configure()`. (#336) - A new instrumentation naming scheme is implemented to avoid package name conflicts for instrumented packages while still remaining discoverable. (#359) - `google.golang.org/grpc` -> `google.golang.org/grpc/otelgrpc` - `go.mongodb.org/mongo-driver` -> `go.mongodb.org/mongo-driver/mongo/otelmongo` - `net/http` -> `net/http/otelhttp` - `net/http/httptrace` -> `net/http/httptrace/otelhttptrace` - `github.com/labstack/echo` -> `github.com/labstack/echo/otelecho` - `github.com/bradfitz/gomemcache` -> `github.com/bradfitz/gomemcache/memcache/otelmemcache` - `github.com/gin-gonic/gin` -> `github.com/gin-gonic/gin/otelgin` - `github.com/gocql/gocql` -> `github.com/gocql/gocql/otelgocql` - `github.com/emicklei/go-restful` -> `github.com/emicklei/go-restful/otelrestful` - `github.com/Shopify/sarama` -> `github.com/Shopify/sarama/otelsarama` - `github.com/gorilla/mux` -> `github.com/gorilla/mux/otelmux` - `github.com/astaxie/beego` -> `github.com/astaxie/beego/otelbeego` - `gopkg.in/macaron.v1` -> `gopkg.in/macaron.v1/otelmacaron` - Rename `OTelBeegoHandler` to `Handler` in the `go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego` package. (#359) - Replace `WithTracer` with `WithTracerProvider` in the `go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron` instrumentation. (#374) ## [0.11.0] - 2020-08-25 ### Added - Top-level `Version()` and `SemVersion()` functions defining the current version of the contrib package. (#225) - Instrumentation for the `github.com/astaxie/beego` package. (#200) - Instrumentation for the `github.com/bradfitz/gomemcache` package. (#204) - Host metrics instrumentation. (#231) - Cortex histogram and distribution support. (#237) - Cortex example project. (#238) - Cortex HTTP authentication. (#246) ### Changed - Remove service name as a parameter of Sarama instrumentation. (#221) - Replace `WithTracer` with `WithTracerProvider` in Sarama instrumentation. (#221) - Switch to use common top-level module `SemVersion()` when creating versioned tracer in `bradfitz/gomemcache`. (#226) - Use `IntegrationShouldRun` in `gomemcache_test`. (#254) - Use Go 1.15 for CI builds. (#236) - Improved configuration for `runtime` instrumentation. (#224) ### Fixed - Update dependabot configuration to include newly added `bradfitz/gomemcache` package. (#226) - Correct `runtime` instrumentation name. (#241) ## [0.10.1] - 2020-08-13 ### Added - The `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc` module has been added to replace the instrumentation that had previoiusly existed in the `go.opentelemetry.io/otel/instrumentation/grpctrace` package. (#189) - Instrumentation for the stdlib `net/http` and `net/http/httptrace` packages. (#190) - Initial Cortex exporter. (#202, #205, #210, #211, #215) ### Fixed - Bump google.golang.org/grpc from 1.30.0 to 1.31.0. (#166) - Bump go.mongodb.org/mongo-driver from 1.3.5 to 1.4.0 in /instrumentation/go.mongodb.org/mongo-driver. (#170) - Bump google.golang.org/grpc in /instrumentation/github.com/gin-gonic/gin. (#173) - Bump google.golang.org/grpc in /instrumentation/github.com/labstack/echo. (#176) - Bump google.golang.org/grpc from 1.30.0 to 1.31.0 in /instrumentation/github.com/Shopify/sarama. (#179) - Bump cloud.google.com/go from 0.61.0 to 0.63.0 in /detectors/gcp. (#181, #199) - Bump github.com/aws/aws-sdk-go from 1.33.15 to 1.34.1 in /detectors/aws. (#184, #192, #193, #198, #201, #203) - Bump github.com/golangci/golangci-lint from 1.29.0 to 1.30.0 in /tools. (#186) - Setup CI to run tests that require external resources (Cassandra and MongoDB). (#191) - Bump github.com/Shopify/sarama from 1.26.4 to 1.27.0 in /instrumentation/github.com/Shopify/sarama. (#206) ## [0.10.0] - 2020-07-31 This release upgrades its [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.10.0) dependency to v0.10.0 and includes new instrumentation for popular Kafka and Cassandra clients. ### Added - A detector that generate resources from GCE instance. (#132) - A detector that generate resources from AWS instances. (#139) - Instrumentation for the Kafka client github.com/Shopify/sarama. (#134, #153) - Links and status message for mock span in the internal testing library. (#134) - Instrumentation for the Cassandra client github.com/gocql/gocql. (#137) - A detector that generate resources from GKE clusters. (#154) ### Fixed - Bump github.com/aws/aws-sdk-go from 1.33.8 to 1.33.15 in /detectors/aws. (#155, #157, #159, #162) - Bump github.com/golangci/golangci-lint from 1.28.3 to 1.29.0 in /tools. (#146) ## [0.9.0] - 2020-07-20 This release upgrades its [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.9.0) dependency to v0.9.0. ### Fixed - Bump github.com/emicklei/go-restful/v3 from 3.0.0 to 3.2.0 in /instrumentation/github.com/emicklei/go-restful. (#133) - Update dependabot configuration to correctly check all included packages. (#131) - Update `RELEASING.md` with correct `tag.sh` command. (#130) ## [0.8.0] - 2020-07-10 This release upgrades its [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.8.0) dependency to v0.8.0, includes minor fixes, and new instrumentation. ### Added - Create this `CHANGELOG.md`. (#114) - Add `emicklei/go-restful/v3` trace instrumentation. (#115) ### Changed - Update `CONTRIBUTING.md` to ask for updates to `CHANGELOG.md` with each pull request. (#114) - Move all `github.com` package instrumentation under a `github.com` directory. (#118) ### Fixed - Update README to include information about external instrumentation. To start, this includes native instrumentation found in the `go-redis/redis` package. (#117) - Bump github.com/golangci/golangci-lint from 1.27.0 to 1.28.2 in /tools. (#122, #123, #125) - Bump go.mongodb.org/mongo-driver from 1.3.4 to 1.3.5 in /instrumentation/go.mongodb.org/mongo-driver. (#124) ## [0.7.0] - 2020-06-29 This release upgrades its [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.7.0) dependency to v0.7.0. ### Added - Create `RELEASING.md` instructions. (#101) - Apply transitive dependabot go.mod updates as part of a new automatic Github workflow. (#94) - New dependabot integration to automate package upgrades. (#61) - Add automatic tag generation script for release. (#60) ### Changed - Upgrade Datadog metrics exporter to include Resource tags. (#46) - Added output validation to Datadog example. (#96) - Move Macaron package to match layout guidelines. (#92) - Update top-level README and instrumentation README. (#92) - Bump google.golang.org/grpc from 1.29.1 to 1.30.0. (#99) - Bump github.com/golangci/golangci-lint from 1.21.0 to 1.27.0 in /tools. (#77) - Bump go.mongodb.org/mongo-driver from 1.3.2 to 1.3.4 in /instrumentation/go.mongodb.org/mongo-driver. (#76) - Bump github.com/stretchr/testify from 1.5.1 to 1.6.1. (#74) - Bump gopkg.in/macaron.v1 from 1.3.5 to 1.3.9 in /instrumentation/macaron. (#68) - Bump github.com/gin-gonic/gin from 1.6.2 to 1.6.3 in /instrumentation/gin-gonic/gin. (#73) - Bump github.com/DataDog/datadog-go from 3.5.0+incompatible to 3.7.2+incompatible in /exporters/metric/datadog. (#78) - Replaced `internal/trace/http.go` helpers with `api/standard` helpers from otel-go repo. (#112) ## [0.6.1] - 2020-06-08 First official tagged release of `contrib` repository. ### Added - `labstack/echo` trace instrumentation (#42) - `mongodb` trace instrumentation (#26) - Go Runtime metrics (#9) - `gorilla/mux` trace instrumentation (#19) - `gin-gonic` trace instrumentation (#15) - `macaron` trace instrumentation (#20) - `dogstatsd` metrics exporter (#10) - `datadog` metrics exporter (#22) - Tags to all modules in repository - Repository folder structure and automated build (#3) ### Changes - Prefix support for dogstatsd (#34) - Update Go Runtime package to use batch observer (#44) [Unreleased]: https://github.com/open-telemetry/opentelemetry-go-contrib/compare/v1.17.0...HEAD [1.17.0/0.42.0/0.11.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.17.0 [1.17.0-rc.1/0.42.0-rc.1/0.11.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.17.0-rc.1 [1.16.1/0.41.1/0.10.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.16.1 [1.16.0/0.41.0/0.10.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.16.0 [1.16.0-rc.2/0.41.0-rc.2/0.10.0-rc.2]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.16.0-rc.2 [1.16.0-rc.1/0.41.0-rc.1/0.10.0-rc.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.16.0-rc.1 [1.15.0/0.40.0/0.9.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.15.0 [1.14.0/0.39.0/0.8.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.14.0 [1.13.0/0.38.0/0.7.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.13.0 [1.12.0/0.37.0/0.6.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.12.0 [1.11.1/0.36.4/0.5.2]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.11.1 [1.11.0/0.36.3/0.5.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.11.0 [0.36.2]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/zpages/v0.36.2 [0.36.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/zpages/v0.36.1 [0.36.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/zpages/v0.36.0 [1.10.0/0.35.0/0.5.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.10.0 [1.9.0/0.34.0/0.4.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.9.0 [1.8.0/0.33.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.8.0 [1.7.0/0.32.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.7.0 [1.6.0/0.31.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.6.0 [1.5.0/0.30.0/0.1.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.5.0 [1.4.0/0.29.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.4.0 [1.3.0/0.28.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.3.0 [1.2.0/0.27.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.2.0 [1.1.1/0.26.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.1.1 [1.1.0/0.26.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.1.0 [1.0.0/0.25.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v1.0.0 [0.24.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.24.0 [0.23.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.23.0 [0.22.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.22.0 [0.21.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.21.0 [0.20.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.20.0 [0.19.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.19.0 [0.18.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.18.0 [0.17.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.17.0 [0.16.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.16.0 [0.15.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.15.1 [0.15.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.15.0 [0.14.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.14.0 [0.13.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.13.0 [0.12.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.12.0 [0.11.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.11.0 [0.10.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.10.1 [0.10.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.10.0 [0.9.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.9.0 [0.8.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.8.0 [0.7.0]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.7.0 [0.6.1]: https://github.com/open-telemetry/opentelemetry-go-contrib/releases/tag/v0.6.1 [Go 1.20]: https://go.dev/doc/go1.20 [Go 1.19]: https://go.dev/doc/go1.19 [Go 1.18]: https://go.dev/doc/go1.18 open-telemetry-opentelemetry-go-contrib-2135499/CODEOWNERS000066400000000000000000000103061443314701600232160ustar00rootroot00000000000000##################################################### # # List of approvers for this repository # ##################################################### # # Learn about membership in OpenTelemetry community: # https://github.com/open-telemetry/community/blob/main/community-membership.md # # # Learn about CODEOWNERS file format: # https://help.github.com/en/articles/about-code-owners # # NOTE: Lines should be entered in the following format: # /.. # instrumentation/net/http/otelhttp/ @open-telemetry/collector-go-approvers @madvikinggod @mralias # Path separator and minimum of 1 space between component path and owners is # important for validation steps # * @open-telemetry/go-approvers CODEOWNERS @MrAlias @Aneurysm9 @MadVikingGod detectors/aws/ @open-telemetry/go-approvers @Aneurysm9 detectors/gcp/ @open-telemetry/go-approvers @dashpole instrumentation/github.com/astaxie/beego/otelbeego/ @open-telemetry/go-approvers instrumentation/github.com/aws/aws-lambda-go/otellambda/ @open-telemetry/go-approvers @Aneurysm9 instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/ @open-telemetry/go-approvers @Aneurysm9 instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/ @open-telemetry/go-approvers instrumentation/github.com/emicklei/go-restful/otelrestful/ @open-telemetry/go-approvers instrumentation/github.com/gin-gonic/gin/otelgin/ @open-telemetry/go-approvers @hanyuancheung instrumentation/github.com/go-kit/kit/otelkit/ @open-telemetry/go-approvers instrumentation/github.com/gocql/gocql/otelgocql/ @open-telemetry/go-approvers instrumentation/github.com/gorilla/mux/otelmux/ @open-telemetry/go-approvers instrumentation/github.com/labstack/echo/otelecho/ @open-telemetry/go-approvers instrumentation/github.com/Shopify/sarama/otelsarama/ @open-telemetry/go-approvers @pellared @hanyuancheung instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/ @open-telemetry/go-approvers instrumentation/google.golang.org/grpc/otelgrpc/ @open-telemetry/go-approvers @dashpole @hanyuancheung instrumentation/gopkg.in/macaron.v1/otelmacaron/ @open-telemetry/go-approvers instrumentation/host/ @open-telemetry/go-approvers @MadVikingGod instrumentation/net/http/httptrace/otelhttptrace/ @open-telemetry/go-approvers @Aneurysm9 @dmathieu instrumentation/net/http/otelhttp/ @open-telemetry/go-approvers @Aneurysm9 @dmathieu instrumentation/runtime/ @open-telemetry/go-approvers @MadVikingGod propagators/autoprop/ @open-telemetry/go-approvers @MrAlias propagators/aws/ @open-telemetry/go-approvers @Aneurysm9 propagators/b3/ @open-telemetry/go-approvers @pellared propagators/jaeger/ @open-telemetry/go-approvers propagators/opencensus/ @open-telemetry/go-approvers @dashpole propagators/ot/ @open-telemetry/go-approvers samplers/aws/xray/ @open-telemetry/go-approvers @Aneurysm9 samplers/jaegerremote/ @open-telemetry/go-approvers samplers/probability/consistent/ @open-telemetry/go-approvers @MadVikingGod zpages/ @open-telemetry/go-approvers instrgen/ @open-telemetry/go-approvers @open-telemetry/go-instrumentation-approvers @MrAlias @pdelewski open-telemetry-opentelemetry-go-contrib-2135499/CONTRIBUTING.md000066400000000000000000000121501443314701600240530ustar00rootroot00000000000000# Contributing to opentelemetry-go-contrib Welcome to the OpenTelemetry Go contrib repository! Thank you for your interest in contributing to this project. Before you start please be sure to read through these contributing requirements and recommendations. ## Become a Contributor All contributions to this project MUST be licensed under this project's [license](LICENSE). You will need to sign the [CNCF CLA](https://identity.linuxfoundation.org/projects/cncf) before your contributions will be accepted. ## Filing Issues Sensitive security-related issues should be reported to . See the [security policy](https://github.com/open-telemetry/opentelemetry-go-contrib/security/policy) for details. When reporting bugs, please be sure to include the following. - What version of Go and opentelemetry-go-contrib are you using? - What operating system and processor architecture are you using? - What did you do? - What did you expect to see? - What did you see instead? For instrumentation requests, please see the [instrumentation documentation](./instrumentation/README.md#new-instrumentation). ## Contributing Code The project welcomes code patches, but to make sure things are well coordinated you should discuss any significant change before starting the work. It's recommended that you signal your intention to contribute in the issue tracker, either by [filing a new issue](https://github.com/open-telemetry/opentelemetry-go-contrib/issues/new) or by claiming an [existing one](https://github.com/open-telemetry/opentelemetry-go-contrib/issues). ### Style Guide * Code should conform to the [opentelemetry-go Style Guide](https://github.com/open-telemetry/opentelemetry-go/blob/main/CONTRIBUTING.md#style-guide). * Make sure to run `make precommit` - this will find and fix issues with the code formatting. ### Pull Requests All pull requests need to be made from [a fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) of this repository. Changes should be made using [the GitHub flow](https://guides.github.com/introduction/flow/) and submitted as a pull request to this repository. A pull request is considered ready to merge when the following criteria are meet. * It has received two approvals from Approvers/Maintainers (at different companies). * All feedback has been addressed. Be sure to "Resolve" all comments that have been addressed to signal this. * Any substantive changes submitted after an Approval removes that Approval. You will need to manually clear these prior Approval reviews to indicate to the reviewer that they need to resubmit their review. This includes changes resulting from other feedback. Unless the approver explicitly stated that their approval will persist across changes it should be assumed that the pull request needs their review again. Other project members (e.g. approvers, maintainers) can help with this if there are any questions or if you forget to clear reviews. * If the changes are not trivial, cosmetic, or for documentation or dependencies only, the pull request will need to be open for review for at least one working day. This gives people reasonable time to review. * `CHANGELOG.md` has been updated to reflect what has been added, changed, removed, or fixed from the end users perspective. See [how to keep a changelog](https://keepachangelog.com/en/1.0.0/). * Urgent fixes can take exception as long as it has been actively communicated. Any Maintainer can merge the pull request once it is ready to merge. ### Draft Pull Requests It can be helpful at times to publish your incomplete changes. To do this create [a draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/). Additionally, you can prefix the pull request title with `[WIP]`. ## Where to Get Help You can connect with us in our [slack channel](https://cloud-native.slack.com/archives/C01NPAXACKT). The Go special interest group (SIG) meets regularly. See the OpenTelemetry [community](https://github.com/open-telemetry/community#golang-sdk) repo for information on this and other language SIGs. See the [public meeting notes](https://docs.google.com/document/d/1A63zSWX0x2CyCK_LoNhmQC4rqhLpYXJzXbEPDUQ2n6w/edit#heading=h.9tngw7jdwd6b) for a summary description of past meetings. ## Approvers and Maintainers Approvers: - [Evan Torrie](https://github.com/evantorrie), Verizon Media - [Josh MacDonald](https://github.com/jmacd), LightStep - [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics - [David Ashpole](https://github.com/dashpole), Google - [Robert Pająk](https://github.com/pellared), Splunk - [Chester Cheung](https://github.com/hanyuancheung), Tencent - [Damien Mathieu](https://github.com/dmathieu), Elastic Maintainers: - [Aaron Clawson](https://github.com/MadVikingGod), LightStep - [Anthony Mirabella](https://github.com/Aneurysm9), Amazon - [Tyler Yahn](https://github.com/MrAlias), Splunk Emeritus: - [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep ### Become an Approver or a Maintainer See the [community membership document in OpenTelemetry community repo](https://github.com/open-telemetry/community/blob/main/community-membership.md). open-telemetry-opentelemetry-go-contrib-2135499/LICENSE000066400000000000000000000261351443314701600226370ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. open-telemetry-opentelemetry-go-contrib-2135499/Makefile000066400000000000000000000237671443314701600233020ustar00rootroot00000000000000# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. TOOLS_MOD_DIR := ./tools ALL_DOCS := $(shell find . -name '*.md' -type f | sort) ALL_GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort) OTEL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(ALL_GO_MOD_DIRS)) ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | grep -E -v '^./example|^$(TOOLS_MOD_DIR)' | sort) # URLs to check if all contrib entries exist in the registry. REGISTRY_BASE_URL = https://raw.githubusercontent.com/open-telemetry/opentelemetry.io/main/content/en/registry CONTRIB_REPO_URL = https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main GO = go TIMEOUT = 60 .DEFAULT_GOAL := precommit .PHONY: precommit ci precommit: generate dependabot-generate license-check misspell go-mod-tidy golangci-lint-fix test-default ci: generate dependabot-check license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage # Tools .PHONY: tools TOOLS = $(CURDIR)/.tools $(TOOLS): @mkdir -p $@ $(TOOLS)/%: | $(TOOLS) cd $(TOOLS_MOD_DIR) && \ $(GO) build -o $@ $(PACKAGE) GOLANGCI_LINT = $(TOOLS)/golangci-lint $(GOLANGCI_LINT): PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint MISSPELL = $(TOOLS)/misspell $(MISSPELL): PACKAGE=github.com/client9/misspell/cmd/misspell GOCOVMERGE = $(TOOLS)/gocovmerge $(GOCOVMERGE): PACKAGE=github.com/wadey/gocovmerge STRINGER = $(TOOLS)/stringer $(STRINGER): PACKAGE=golang.org/x/tools/cmd/stringer PORTO = $(TOOLS)/porto $(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto MULTIMOD = $(TOOLS)/multimod $(MULTIMOD): PACKAGE=go.opentelemetry.io/build-tools/multimod DBOTCONF = $(TOOLS)/dbotconf $(TOOLS)/dbotconf: PACKAGE=go.opentelemetry.io/build-tools/dbotconf CROSSLINK = $(TOOLS)/crosslink $(CROSSLINK): PACKAGE=go.opentelemetry.io/build-tools/crosslink GOTMPL = $(TOOLS)/gotmpl $(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl tools: $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(MULTIMOD) $(DBOTCONF) $(CROSSLINK) $(GOTMPL) # Generate .PHONY: generate generate: go-generate vanity-import-fix .PHONY: go-generate go-generate: $(OTEL_GO_MOD_DIRS:%=go-generate/%) go-generate/%: DIR=$* go-generate/%: | $(STRINGER) $(PORTO) @echo "$(GO) generate $(DIR)/..." \ && cd $(DIR) \ && PATH="$(TOOLS):$${PATH}" $(GO) generate ./... .PHONY: vanity-import-fix vanity-import-fix: | $(PORTO) @$(PORTO) --include-internal -w . # Build .PHONY: build build: $(OTEL_GO_MOD_DIRS:%=build/%) $(OTEL_GO_MOD_DIRS:%=build-tests/%) build/%: DIR=$* build/%: @echo "$(GO) build $(DIR)/..." \ && cd $(DIR) \ && $(GO) build ./... build-tests/%: DIR=$* build-tests/%: @echo "$(GO) build tests $(DIR)/..." \ && cd $(DIR) \ && $(GO) list ./... \ | grep -v third_party \ | xargs $(GO) test -vet=off -run xxxxxMatchNothingxxxxx >/dev/null # Linting .PHONY: golangci-lint golangci-lint-fix golangci-lint-fix: ARGS=--fix golangci-lint-fix: golangci-lint golangci-lint: $(OTEL_GO_MOD_DIRS:%=golangci-lint/%) golangci-lint/%: DIR=$* golangci-lint/%: | $(GOLANGCI_LINT) @echo 'golangci-lint $(if $(ARGS),$(ARGS) ,)$(DIR)' \ && cd $(DIR) \ && $(GOLANGCI_LINT) run --allow-serial-runners $(ARGS) .PHONY: crosslink crosslink: | $(CROSSLINK) @echo "Updating intra-repository dependencies in all go modules" \ && $(CROSSLINK) --root=$(shell pwd) --prune .PHONY: go-mod-tidy go-mod-tidy: $(ALL_GO_MOD_DIRS:%=go-mod-tidy/%) go-mod-tidy/%: DIR=$* go-mod-tidy/%: @echo "$(GO) mod tidy in $(DIR)" \ && cd $(DIR) \ && $(GO) mod tidy -compat=1.19 .PHONY: misspell misspell: | $(MISSPELL) @$(MISSPELL) -w $(ALL_DOCS) .PHONY: vanity-import-check vanity-import-check: | $(PORTO) @$(PORTO) --include-internal -l . || echo "(run: make vanity-import-fix)" .PHONY: lint lint: go-mod-tidy golangci-lint misspell .PHONY: license-check license-check: @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ exit 1; \ fi .PHONY: registry-links-check registry-links-check: @checkRes=$$( \ for f in $$( find ./instrumentation ./exporters ./detectors ! -path './instrumentation/net/*' -type f -name 'go.mod' -exec dirname {} \; | egrep -v '/example|/utils' | sort ) \ ./instrumentation/net/http; do \ TYPE="instrumentation"; \ if $$(echo "$$f" | grep -q "exporters"); then \ TYPE="exporter"; \ fi; \ if $$(echo "$$f" | grep -q "detectors"); then \ TYPE="detector"; \ fi; \ NAME=$$(echo "$$f" | sed -e 's/.*\///' -e 's/.*otel//'); \ LINK=$(CONTRIB_REPO_URL)/$$(echo "$$f" | sed -e 's/..//' -e 's/\/otel.*$$//'); \ if ! $$(curl -s $(REGISTRY_BASE_URL)/$${TYPE}-go-$${NAME}.md | grep -q "$${LINK}"); then \ echo "$$f"; \ fi \ done; \ ); \ if [ -n "$$checkRes" ]; then \ echo "WARNING: registry link check failed for the following packages:"; echo "$${checkRes}"; \ fi DEPENDABOT_CONFIG = .github/dependabot.yml .PHONY: dependabot-check dependabot-check: | $(DBOTCONF) @$(DBOTCONF) verify $(DEPENDABOT_CONFIG) || echo "(run: make dependabot-generate)" .PHONY: dependabot-generate dependabot-generate: | $(DBOTCONF) @$(DBOTCONF) generate > $(DEPENDABOT_CONFIG) .PHONY: check-clean-work-tree check-clean-work-tree: @if ! git diff --quiet; then \ echo; \ echo 'Working tree is not clean, did you forget to run "make precommit"?'; \ echo; \ git status; \ exit 1; \ fi # Tests TEST_TARGETS := test-default test-bench test-short test-verbose test-race .PHONY: $(TEST_TARGETS) test test-default test-race: ARGS=-race test-bench: ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=. test-short: ARGS=-short test-verbose: ARGS=-v $(TEST_TARGETS): test test: $(OTEL_GO_MOD_DIRS:%=test/%) test/%: DIR=$* test/%: @echo "$(GO) test -timeout $(TIMEOUT)s $(ARGS) $(DIR)/..." \ && cd $(DIR) \ && $(GO) test -timeout $(TIMEOUT)s $(ARGS) ./... COVERAGE_MODE = atomic COVERAGE_PROFILE = coverage.out .PHONY: test-coverage test-coverage: $(ALL_COVERAGE_MOD_DIRS:%=test-coverage/%) | $(GOCOVMERGE) @printf "" > coverage.txt \ && $(GOCOVMERGE) $$(find . -name $(COVERAGE_PROFILE)) > coverage.txt test-coverage/%: DIR=$* test-coverage/%: @set -e; \ CMD="$(GO) test -race -covermode=$(COVERAGE_MODE) -coverprofile=$(COVERAGE_PROFILE)"; \ echo "$(DIR)" | grep -q 'test$$' \ && CMD="$$CMD -coverpkg=go.opentelemetry.io/contrib/$$( dirname "$(DIR)" | sed -e "s/^\.\///g" )/..."; \ echo "$$CMD $(DIR)/..."; \ cd "$(DIR)" \ && $$CMD ./... \ && $(GO) tool cover -html=coverage.out -o coverage.html; .PHONY: test-gocql test-gocql: @if ./tools/should_build.sh gocql; then \ set -e; \ docker run --name cass-integ --rm -p 9042:9042 -d cassandra:3; \ CMD=cassandra IMG_NAME=cass-integ ./tools/wait.sh; \ (cd instrumentation/github.com/gocql/gocql/otelgocql/test/ && \ $(GO) test \ -covermode=$(COVERAGE_MODE) \ -coverprofile=$(COVERAGE_PROFILE) \ -coverpkg=go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/... \ ./... \ && $(GO) tool cover -html=$(COVERAGE_PROFILE) -o coverage.html); \ cp ./instrumentation/github.com/gocql/gocql/otelgocql/test/coverage.out ./; \ docker stop cass-integ; \ fi .PHONY: test-mongo-driver test-mongo-driver: @if ./tools/should_build.sh mongo-driver; then \ set -e; \ docker run --name mongo-integ --rm -p 27017:27017 -d mongo; \ CMD=mongo IMG_NAME=mongo-integ ./tools/wait.sh; \ (cd instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test && \ $(GO) test \ -covermode=$(COVERAGE_MODE) \ -coverprofile=$(COVERAGE_PROFILE) \ -coverpkg=go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/... \ ./... \ && $(GO) tool cover -html=$(COVERAGE_PROFILE) -o coverage.html); \ cp ./instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/coverage.out ./; \ docker stop mongo-integ; \ fi .PHONY: test-gomemcache test-gomemcache: @if ./tools/should_build.sh gomemcache; then \ set -e; \ docker run --name gomemcache-integ --rm -p 11211:11211 -d memcached; \ CMD=gomemcache IMG_NAME=gomemcache-integ ./tools/wait.sh; \ (cd instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test && \ $(GO) test \ -covermode=$(COVERAGE_MODE) \ -coverprofile=$(COVERAGE_PROFILE) \ -coverpkg=go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/... \ ./... \ && $(GO) tool cover -html=$(COVERAGE_PROFILE) -o coverage.html); \ docker stop gomemcache-integ ; \ cp ./instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test/coverage.out ./; \ fi # Releasing COREPATH ?= "../opentelemetry-go" .PHONY: sync-core sync-core: | $(MULTIMOD) @[ ! -d $COREPATH ] || ( echo ">> Path to core repository must be set in COREPATH and must exist"; exit 1 ) $(MULTIMOD) verify && $(MULTIMOD) sync -a -o ${COREPATH} .PHONY: prerelease prerelease: | $(MULTIMOD) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) $(MULTIMOD) verify && $(MULTIMOD) prerelease -m ${MODSET} COMMIT ?= "HEAD" .PHONY: add-tags add-tags: | $(MULTIMOD) @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) $(MULTIMOD) verify && $(MULTIMOD) tag -m ${MODSET} -c ${COMMIT} open-telemetry-opentelemetry-go-contrib-2135499/README.md000066400000000000000000000072461443314701600231130ustar00rootroot00000000000000# OpenTelemetry-Go Contrib [![build_and_test](https://github.com/open-telemetry/opentelemetry-go-contrib/workflows/build_and_test/badge.svg)](https://github.com/open-telemetry/opentelemetry-go-contrib/actions?query=workflow%3Abuild_and_test+branch%3Amain) [![codecov.io](https://codecov.io/gh/open-telemetry/opentelemetry-go-contrib/coverage.svg?branch=main)](https://app.codecov.io/gh/open-telemetry/opentelemetry-go-contrib?branch=main) [![Docs](https://godoc.org/go.opentelemetry.io/contrib?status.svg)](https://pkg.go.dev/go.opentelemetry.io/contrib) [![Go Report Card](https://goreportcard.com/badge/go.opentelemetry.io/contrib)](https://goreportcard.com/report/go.opentelemetry.io/contrib) [![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01NPAXACKT) Collection of 3rd-party packages for [OpenTelemetry-Go](https://github.com/open-telemetry/opentelemetry-go). ## Contents - [Instrumentation](./instrumentation/): Packages providing OpenTelemetry instrumentation for 3rd-party libraries. - [Propagators](./propagators/): Packages providing OpenTelemetry context propagators for 3rd-party propagation formats. - [Detectors](./detectors/): Packages providing OpenTelemetry resource detectors for 3rd-party cloud computing environments. - [Samplers](./samplers/): Packages providing additional implementations of OpenTelemetry samplers. ## Project Status This project contains both stable and unstable modules. Refer to the module for its version or our [versioning manifest](./versions.yaml). Project versioning information and stability guarantees can be found in the [versioning documentation](https://github.com/open-telemetry/opentelemetry-go/blob/a724cf884287e04785eaa91513d26a6ef9699288/VERSIONING.md). Progress and status specific to this repository is tracked in our local [project boards](https://github.com/open-telemetry/opentelemetry-go-contrib/projects?query=is%3Aopen) and [milestones](https://github.com/open-telemetry/opentelemetry-go-contrib/milestones). ### Compatibility OpenTelemetry-Go Contrib ensures compatibility with the current supported versions of the [Go language](https://golang.org/doc/devel/release#policy): > Each major Go release is supported until there are two newer major releases. > For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release. For versions of Go that are no longer supported upstream, opentelemetry-go-contrib will stop ensuring compatibility with these versions in the following manner: - A minor release of opentelemetry-go-contrib will be made to add support for the new supported release of Go. - The following minor release of opentelemetry-go-contrib will remove compatibility testing for the oldest (now archived upstream) version of Go. This, and future, releases of opentelemetry-go-contrib may include features only supported by the currently supported versions of Go. This project is tested on the following systems. | OS | Go Version | Architecture | | ------- | ---------- | ------------ | | Ubuntu | 1.20 | amd64 | | Ubuntu | 1.19 | amd64 | | Ubuntu | 1.20 | 386 | | Ubuntu | 1.19 | 386 | | MacOS | 1.20 | amd64 | | MacOS | 1.19 | amd64 | | Windows | 1.20 | amd64 | | Windows | 1.19 | amd64 | | Windows | 1.20 | 386 | | Windows | 1.19 | 386 | While this project should work for other systems, no compatibility guarantees are made for those systems currently. ## Contributing For information on how to contribute, consult [the contributing guidelines](./CONTRIBUTING.md) open-telemetry-opentelemetry-go-contrib-2135499/RELEASING.md000066400000000000000000000075461443314701600234720ustar00rootroot00000000000000# Release Process This project uses the [`multimod` releaser tool](https://github.com/open-telemetry/opentelemetry-go-build-tools/tree/main/multimod) to manage releases. This document will walk you through how to perform a release using this tool for this repository. ## Start a release First, decide which module sets will have their versions changed and what those versions will be. If you are making a release to upgrade the upstream go.opentelemetry.io/otel packages, all module sets will likely need to be released. ### Create a release branch Update the versions of the module sets you have identified in `versions.yaml`. Commit this change to a new release branch. ### Upgrade go.opentelemetry.io/otel packages If the upstream go.opentelemetry.io/otel project has made a release, this project needs to be upgraded to use that release. ```sh make sync-core COREPATH= ``` This will use `multimod` to upgrade all go.opentelemetry.io/otel packages to the latest tag found in the local copy of the project. Be sure to have this project up to date. Commit these changes to your release branch. ### Update module set versions Set the version for all the module sets you have identified to be released. ```sh make prerelease MODSET= ``` This will use `multimod` to upgrade the module's versions and create a new "prerelease" branch for the changes. Verify the changes that were made. ```sh git diff HEAD..prerelease__ ``` Fix any issues if they exist in that prerelease branch, and when ready, merge it into your release branch. ```sh git merge prerelease__ ``` ### Update the CHANGELOG.md Update the [Changelog](./CHANGELOG.md). Make sure only changes relevant to this release are included and the changes are communicated in language that non-contributors to the project can understand. Double check there is no change missing by looking directly at the commits since the last release tag. ```sh git --no-pager log --pretty=oneline "..HEAD" ``` Be sure to update all the appropriate links at the bottom of the file. Finally, commit this change to your release branch. ### Make a Pull Request Push your release branch and create a pull request for the changes. Be sure to include the curated changes your included in the changelog in the description. Especially include the change PR references, as this will help show viewers of the repository looking at these PRs that they are included in the release. ## Tag a release Once the Pull Request with all the version changes has been approved and merged it is time to tag the merged commit. ***IMPORTANT***: It is critical you use the same tag that you used in the Pre-Release step! Failure to do so will leave things in a broken state. As long as you do not change `versions.yaml` between pre-release and this step, things should be fine. 1. For each module set that will be released, run the `add-tags` make target using the `` of the commit on the main branch for the merged Pull Request. ```sh make add-tags MODSET= COMMIT= ``` It should only be necessary to provide an explicit `COMMIT` value if the current `HEAD` of your working directory is not the correct commit. 2. Push tags to the upstream remote (not your fork: `github.com/open-telemetry/opentelemetry-go-contrib.git`). Make sure you push all sub-modules as well. ```sh export VERSION="" for t in $( git tag -l | grep "$VERSION" ); do git push upstream "$t"; done ``` ## Release Finally create a Release on GitHub. If you are release multiple versions for different module sets, be sure to use the stable release tag but be sure to include each version in the release title (i.e. `Release v1.0.0/v0.25.0`). The release body should include all the curated changes from the Changelog for this release. open-telemetry-opentelemetry-go-contrib-2135499/detectors/000077500000000000000000000000001443314701600236175ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/000077500000000000000000000000001443314701600244115ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/README.md000066400000000000000000000020711443314701600256700ustar00rootroot00000000000000# AWS Resource Detectors ## EC2 Sample code snippet to initialize EC2 resource detector ``` // Instantiate a new EC2 Resource detector ec2ResourceDetector := ec2.NewResourceDetector() resource, err := ec2ResourceDetector.Detect(context.Background()) ``` EC2 resource detector captures following EC2 instance environment attributes ``` region availability_zone account.id host.id host.image.id host.type ``` ## ECS Sample code snippet to initialize ECS resource detector ``` // Instantiate a new ECS Resource detector ecsResourceDetector := ecs.NewResourceDetector() resource, err := ecsResourceDetector.Detect(context.Background()) ``` ECS resource detector captures following ECS environment attributes ``` container.name container.id ``` ## EKS Sample code snippet to initialize EKS resource detector ``` // Instantiate a new EKS Resource detector eksResourceDetector := eks.NewResourceDetector() resource, err := eksResourceDetector.Detect(context.Background()) ``` EKS resource detector captures following EKS environment attributes ``` k8s.cluster.name container.id ``` open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/000077500000000000000000000000001443314701600250625ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/ec2.go000066400000000000000000000077121443314701600260710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ec2 // import "go.opentelemetry.io/contrib/detectors/aws/ec2" import ( "context" "fmt" "net/http" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) type config struct { c Client } // newConfig returns an appropriately configured config. func newConfig(options ...Option) *config { c := new(config) for _, option := range options { option.apply(c) } return c } // Option applies an EC2 detector configuration option. type Option interface { apply(*config) } type optionFunc func(*config) func (fn optionFunc) apply(c *config) { fn(c) } // WithClient sets the ec2metadata client in config. func WithClient(t Client) Option { return optionFunc(func(c *config) { c.c = t }) } func (cfg *config) getClient() Client { return cfg.c } // resource detector collects resource information from EC2 environment. type resourceDetector struct { c Client } // Client implements methods to capture EC2 environment metadata information. type Client interface { Available() bool GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) GetMetadata(p string) (string, error) } // compile time assertion that resourceDetector implements the resource.Detector interface. var _ resource.Detector = (*resourceDetector)(nil) // NewResourceDetector returns a resource detector that will detect AWS EC2 resources. func NewResourceDetector(opts ...Option) resource.Detector { c := newConfig(opts...) return &resourceDetector{c.getClient()} } // Detect detects associated resources when running in AWS environment. func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { client, err := detector.client() if err != nil { return nil, err } if !client.Available() { return nil, nil } doc, err := client.GetInstanceIdentityDocument() if err != nil { return nil, err } attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSEC2, semconv.CloudRegion(doc.Region), semconv.CloudAvailabilityZone(doc.AvailabilityZone), semconv.CloudAccountID(doc.AccountID), semconv.HostID(doc.InstanceID), semconv.HostImageID(doc.ImageID), semconv.HostType(doc.InstanceType), } m := &metadata{client: client} m.add(semconv.HostNameKey, "hostname") attributes = append(attributes, m.attributes...) if len(m.errs) > 0 { err = fmt.Errorf("%w: %s", resource.ErrPartialResource, m.errs) } return resource.NewWithAttributes(semconv.SchemaURL, attributes...), err } func (detector *resourceDetector) client() (Client, error) { if detector.c != nil { return detector.c, nil } s, err := session.NewSession() if err != nil { return nil, err } return ec2metadata.New(s), nil } type metadata struct { client Client errs []error attributes []attribute.KeyValue } func (m *metadata) add(k attribute.Key, n string) { v, err := m.client.GetMetadata(n) if err == nil { m.attributes = append(m.attributes, k.String(v)) return } rf, ok := err.(awserr.RequestFailure) if !ok { m.errs = append(m.errs, fmt.Errorf("%q: %w", n, err)) return } if rf.StatusCode() == http.StatusNotFound { return } m.errs = append(m.errs, fmt.Errorf("%q: %d %s", n, rf.StatusCode(), rf.Code())) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/ec2_test.go000066400000000000000000000133411443314701600271230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ec2 import ( "context" "errors" "net/http" "testing" "time" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func TestAWS_Detect(t *testing.T) { type fields struct { Client Client } type want struct { Error string Partial bool Resource *resource.Resource } usWestInst := func() (ec2metadata.EC2InstanceIdentityDocument, error) { // Example from https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html doc := ec2metadata.EC2InstanceIdentityDocument{ MarketplaceProductCodes: []string{"1abc2defghijklm3nopqrs4tu"}, AvailabilityZone: "us-west-2b", PrivateIP: "10.158.112.84", Version: "2017-09-30", Region: "us-west-2", InstanceID: "i-1234567890abcdef0", InstanceType: "t2.micro", AccountID: "123456789012", PendingTime: time.Date(2016, time.November, 19, 16, 32, 11, 0, time.UTC), ImageID: "ami-5fb8c835", Architecture: "x86_64", } return doc, nil } usWestIDLabels := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSEC2, semconv.CloudRegion("us-west-2"), semconv.CloudAvailabilityZone("us-west-2b"), semconv.CloudAccountID("123456789012"), semconv.HostID("i-1234567890abcdef0"), semconv.HostImageID("ami-5fb8c835"), semconv.HostType("t2.micro"), } testTable := map[string]struct { Fields fields Want want }{ "Unavailable": { Fields: fields{Client: &clientMock{}}, }, "Instance ID Error": { Fields: fields{ Client: &clientMock{available: true, idDoc: func() (ec2metadata.EC2InstanceIdentityDocument, error) { return ec2metadata.EC2InstanceIdentityDocument{}, errors.New("id not available") }}, }, Want: want{Error: "id not available"}, }, "Hostname Not Found": { Fields: fields{ Client: &clientMock{available: true, idDoc: usWestInst, metadata: map[string]meta{}}, }, Want: want{Resource: resource.NewWithAttributes(semconv.SchemaURL, usWestIDLabels...)}, }, "Hostname Response Error": { Fields: fields{ Client: &clientMock{ available: true, idDoc: usWestInst, metadata: map[string]meta{ "hostname": {err: awserr.NewRequestFailure(awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New("response error")), http.StatusInternalServerError, "test-request")}, }, }, }, Want: want{ Error: `partial resource: ["hostname": 500 EC2MetadataError]`, Partial: true, Resource: resource.NewWithAttributes(semconv.SchemaURL, usWestIDLabels...), }, }, "Hostname General Error": { Fields: fields{ Client: &clientMock{ available: true, idDoc: usWestInst, metadata: map[string]meta{ "hostname": {err: errors.New("unknown error")}, }, }, }, Want: want{ Error: `partial resource: ["hostname": unknown error]`, Partial: true, Resource: resource.NewWithAttributes(semconv.SchemaURL, usWestIDLabels...), }, }, "All Available": { Fields: fields{ Client: &clientMock{ available: true, idDoc: usWestInst, metadata: map[string]meta{ "hostname": {value: "ip-12-34-56-78.us-west-2.compute.internal"}, }, }, }, Want: want{Resource: resource.NewWithAttributes( semconv.SchemaURL, semconv.CloudProviderAWS, semconv.CloudPlatformAWSEC2, semconv.CloudRegion("us-west-2"), semconv.CloudAvailabilityZone("us-west-2b"), semconv.CloudAccountID("123456789012"), semconv.HostID("i-1234567890abcdef0"), semconv.HostImageID("ami-5fb8c835"), semconv.HostName("ip-12-34-56-78.us-west-2.compute.internal"), semconv.HostType("t2.micro"), )}, }, } for name, tt := range testTable { tt := tt t.Run(name, func(t *testing.T) { t.Parallel() ec2ResourceDetector := NewResourceDetector(WithClient(tt.Fields.Client)) r, err := ec2ResourceDetector.Detect(context.Background()) assert.Equal(t, tt.Want.Resource, r, "Resource") if tt.Want.Error != "" { require.EqualError(t, err, tt.Want.Error, "Error") assert.Equal(t, tt.Want.Partial, errors.Is(err, resource.ErrPartialResource), "Partial Resource") return } require.NoError(t, err, "Error") }) } } type clientMock struct { available bool idDoc func() (ec2metadata.EC2InstanceIdentityDocument, error) metadata map[string]meta } type meta struct { err error value string } func (c *clientMock) Available() bool { return c.available } func (c *clientMock) GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) { return c.idDoc() } func (c *clientMock) GetMetadata(p string) (string, error) { v, ok := c.metadata[p] if !ok { return "", awserr.NewRequestFailure(awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New("response error")), http.StatusNotFound, "test-request") } return v.value, v.err } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/go.mod000066400000000000000000000012111443314701600261630ustar00rootroot00000000000000module go.opentelemetry.io/contrib/detectors/aws/ec2 go 1.19 require ( github.com/aws/aws-sdk-go v1.44.266 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/go.sum000066400000000000000000000134121443314701600262160ustar00rootroot00000000000000github.com/aws/aws-sdk-go v1.44.266 h1:MWd775dcYf7NrwgcHLtlsIbWoWkX8p4vomfNHr88zH0= github.com/aws/aws-sdk-go v1.44.266/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ec2/version.go000066400000000000000000000017771443314701600271120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ec2 // import "go.opentelemetry.io/contrib/detectors/aws/ec2" // Version is the current release version of the EC2 resource detector. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/000077500000000000000000000000001443314701600251635ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/ecs.go000066400000000000000000000151531443314701600262710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ecs // import "go.opentelemetry.io/contrib/detectors/aws/ecs" import ( "context" "errors" "fmt" "net/http" "os" "runtime" "strings" ecsmetadata "github.com/brunoscheufler/aws-ecs-metadata-go" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const ( // TypeStr is AWS ECS type. TypeStr = "ecs" metadataV3EnvVar = "ECS_CONTAINER_METADATA_URI" metadataV4EnvVar = "ECS_CONTAINER_METADATA_URI_V4" containerIDLength = 64 defaultCgroupPath = "/proc/self/cgroup" ) var ( empty = resource.Empty() errCannotReadContainerName = errors.New("failed to read hostname") errCannotRetrieveLogsGroupMetadataV4 = errors.New("the ECS Metadata v4 did not return a AwsLogGroup name") errCannotRetrieveLogsStreamMetadataV4 = errors.New("the ECS Metadata v4 did not return a AwsLogStream name") ) // Create interface for methods needing to be mocked. type detectorUtils interface { getContainerName() (string, error) getContainerID() (string, error) } // struct implements detectorUtils interface. type ecsDetectorUtils struct{} // resource detector collects resource information from Elastic Container Service environment. type resourceDetector struct { utils detectorUtils } // compile time assertion that ecsDetectorUtils implements detectorUtils interface. var _ detectorUtils = (*ecsDetectorUtils)(nil) // compile time assertion that resource detector implements the resource.Detector interface. var _ resource.Detector = (*resourceDetector)(nil) // NewResourceDetector returns a resource detector that will detect AWS ECS resources. func NewResourceDetector() resource.Detector { return &resourceDetector{ utils: ecsDetectorUtils{}, } } // Detect finds associated resources when running on ECS environment. func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { metadataURIV3 := os.Getenv(metadataV3EnvVar) metadataURIV4 := os.Getenv(metadataV4EnvVar) if len(metadataURIV3) == 0 && len(metadataURIV4) == 0 { return nil, nil } hostName, err := detector.utils.getContainerName() if err != nil { return empty, err } containerID, err := detector.utils.getContainerID() if err != nil { return empty, err } attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSECS, semconv.ContainerName(hostName), semconv.ContainerID(containerID), } if len(metadataURIV4) > 0 { containerMetadata, err := ecsmetadata.GetContainerV4(ctx, &http.Client{}) if err != nil { return empty, err } attributes = append( attributes, semconv.AWSECSContainerARN(containerMetadata.ContainerARN), ) taskMetadata, err := ecsmetadata.GetTaskV4(ctx, &http.Client{}) if err != nil { return empty, err } clusterArn := taskMetadata.Cluster if !strings.HasPrefix(clusterArn, "arn:") { baseArn := containerMetadata.ContainerARN[:strings.LastIndex(containerMetadata.ContainerARN, ":")] clusterArn = fmt.Sprintf("%s:cluster/%s", baseArn, clusterArn) } logAttributes, err := detector.getLogsAttributes(containerMetadata) if err != nil { return empty, err } if len(logAttributes) > 0 { attributes = append(attributes, logAttributes...) } attributes = append( attributes, semconv.AWSECSClusterARN(clusterArn), semconv.AWSECSLaunchtypeKey.String(strings.ToLower(taskMetadata.LaunchType)), semconv.AWSECSTaskARN(taskMetadata.TaskARN), semconv.AWSECSTaskFamily(taskMetadata.Family), semconv.AWSECSTaskRevision(taskMetadata.Revision), ) } return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil } func (detector *resourceDetector) getLogsAttributes(metadata *ecsmetadata.ContainerMetadataV4) ([]attribute.KeyValue, error) { if metadata.LogDriver != "awslogs" { return []attribute.KeyValue{}, nil } logsOptions := metadata.LogOptions if len(logsOptions.AwsLogsGroup) < 1 { return nil, errCannotRetrieveLogsGroupMetadataV4 } if len(logsOptions.AwsLogsStream) < 1 { return nil, errCannotRetrieveLogsStreamMetadataV4 } containerArn := metadata.ContainerARN // https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html const arnPartition = 1 const arnRegion = 3 const arnAccountId = 4 containerArnParts := strings.Split(containerArn, ":") // a valid arn should have at least 6 parts if len(containerArnParts) < 6 { return nil, errCannotRetrieveLogsStreamMetadataV4 } logsRegion := logsOptions.AwsRegion if len(logsRegion) < 1 { logsRegion = containerArnParts[arnRegion] } awsPartition := containerArnParts[arnPartition] awsAccount := containerArnParts[arnAccountId] awsLogGroupArn := strings.Join([]string{"arn", awsPartition, "logs", logsRegion, awsAccount, "log-group", logsOptions.AwsLogsGroup, "*"}, ":") awsLogStreamArn := strings.Join([]string{"arn", awsPartition, "logs", logsRegion, awsAccount, "log-group", logsOptions.AwsLogsGroup, "log-stream", logsOptions.AwsLogsStream}, ":") return []attribute.KeyValue{ semconv.AWSLogGroupNames(logsOptions.AwsLogsGroup), semconv.AWSLogGroupARNs(awsLogGroupArn), semconv.AWSLogStreamNames(logsOptions.AwsLogsStream), semconv.AWSLogStreamARNs(awsLogStreamArn), }, nil } // returns docker container ID from default c group path. func (ecsUtils ecsDetectorUtils) getContainerID() (string, error) { if runtime.GOOS != "linux" { // Cgroups are used only under Linux. return "", nil } fileData, err := os.ReadFile(defaultCgroupPath) if err != nil { // Cgroups file not found. // For example, windows; or when running integration tests outside of a container. return "", nil } splitData := strings.Split(strings.TrimSpace(string(fileData)), "\n") for _, str := range splitData { if len(str) > containerIDLength { return str[len(str)-containerIDLength:], nil } } return "", nil } // returns host name reported by the kernel. func (ecsUtils ecsDetectorUtils) getContainerName() (string, error) { hostName, err := os.Hostname() if err != nil { return "", errCannotReadContainerName } return hostName, nil } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/ecs_test.go000066400000000000000000000122221443314701600273220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ecs import ( "context" "os" "testing" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" metadata "github.com/brunoscheufler/aws-ecs-metadata-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // Create interface for functions that need to be mocked. type MockDetectorUtils struct { mock.Mock } func (detectorUtils *MockDetectorUtils) getContainerID() (string, error) { args := detectorUtils.Called() return args.String(0), args.Error(1) } func (detectorUtils *MockDetectorUtils) getContainerName() (string, error) { args := detectorUtils.Called() return args.String(0), args.Error(1) } // successfully returns resource when process is running on Amazon ECS environment // with no Metadata v4. func TestDetectV3(t *testing.T) { os.Clearenv() _ = os.Setenv(metadataV3EnvVar, "3") detectorUtils := new(MockDetectorUtils) detectorUtils.On("getContainerName").Return("container-Name", nil) detectorUtils.On("getContainerID").Return("0123456789A", nil) attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSECS, semconv.ContainerName("container-Name"), semconv.ContainerID("0123456789A"), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) detector := &resourceDetector{utils: detectorUtils} res, _ := detector.Detect(context.Background()) assert.Equal(t, expectedResource, res, "Resource returned is incorrect") } // returns empty resource when detector cannot read container ID. func TestDetectCannotReadContainerID(t *testing.T) { os.Clearenv() _ = os.Setenv(metadataV3EnvVar, "3") detectorUtils := new(MockDetectorUtils) detectorUtils.On("getContainerName").Return("container-Name", nil) detectorUtils.On("getContainerID").Return("", nil) attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSECS, semconv.ContainerName("container-Name"), semconv.ContainerID(""), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) detector := &resourceDetector{utils: detectorUtils} res, err := detector.Detect(context.Background()) assert.Equal(t, nil, err) assert.Equal(t, expectedResource, res, "Resource returned is incorrect") } // returns empty resource when detector cannot read container Name. func TestDetectCannotReadContainerName(t *testing.T) { os.Clearenv() _ = os.Setenv(metadataV3EnvVar, "3") _ = os.Setenv(metadataV4EnvVar, "4") detectorUtils := new(MockDetectorUtils) detectorUtils.On("getContainerName").Return("", errCannotReadContainerName) detectorUtils.On("getContainerID").Return("0123456789A", nil) detector := &resourceDetector{utils: detectorUtils} res, err := detector.Detect(context.Background()) assert.Equal(t, errCannotReadContainerName, err) assert.Equal(t, 0, len(res.Attributes())) } // returns empty resource when process is not running ECS. func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() detector := &resourceDetector{utils: nil} res, err := detector.Detect(context.Background()) // When not on ECS, the detector should return nil and not error. assert.NoError(t, err, "failure to detect when not on platform must not be an error") assert.Nil(t, res, "failure to detect should return a nil Resource to optimize merge") } // handles alternative aws partitions (e.g. AWS GovCloud). func TestLogsAttributesAlternatePartition(t *testing.T) { os.Clearenv() detector := &resourceDetector{utils: nil} containerMetadata := &metadata.ContainerMetadataV4{ LogDriver: "awslogs", LogOptions: struct { AwsLogsCreateGroup string `json:"awslogs-create-group"` AwsLogsGroup string `json:"awslogs-group"` AwsLogsStream string `json:"awslogs-stream"` AwsRegion string `json:"awslogs-region"` }{ "fake-create", "fake-group", "fake-stream", "", }, ContainerARN: "arn:arn-partition:arn-svc:arn-region:arn-account:arn-resource", } actualAttributes, err := detector.getLogsAttributes(containerMetadata) assert.NoError(t, err, "failure with nonstandard partitition") expectedAttributes := []attribute.KeyValue{ semconv.AWSLogGroupNames(containerMetadata.LogOptions.AwsLogsGroup), semconv.AWSLogGroupARNs("arn:arn-partition:logs:arn-region:arn-account:log-group:fake-group:*"), semconv.AWSLogStreamNames(containerMetadata.LogOptions.AwsLogsStream), semconv.AWSLogStreamARNs("arn:arn-partition:logs:arn-region:arn-account:log-group:fake-group:log-stream:fake-stream"), } assert.Equal(t, expectedAttributes, actualAttributes, "logs attributes are incorrect") } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/go.mod000066400000000000000000000012571443314701600262760ustar00rootroot00000000000000module go.opentelemetry.io/contrib/detectors/aws/ecs go 1.19 require ( github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/go.sum000066400000000000000000000062241443314701600263220ustar00rootroot00000000000000github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf h1:WCnJxXZXx9c8gwz598wvdqmu+YTzB9wx2X1OovK3Le8= github.com/brunoscheufler/aws-ecs-metadata-go v0.0.0-20220812150832-b6b31c6eeeaf/go.mod h1:CeKhh8xSs3WZAc50xABMxu+FlfAAd5PNumo7NfOv7EE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test/000077500000000000000000000000001443314701600261425ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test/ecs_test.go000066400000000000000000000125611443314701600303070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ecs import ( "context" "net/http" "net/http/httptest" "os" "strings" "testing" ecs "go.opentelemetry.io/contrib/detectors/aws/ecs" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "github.com/stretchr/testify/assert" ) const ( metadataV4EnvVar = "ECS_CONTAINER_METADATA_URI_V4" ) // successfully returns resource when process is running on Amazon ECS environment // with Metadata v4 with the EC2 Launch type. func TestDetectV4LaunchTypeEc2(t *testing.T) { testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { if strings.HasSuffix(req.URL.String(), "/task") { content, err := os.ReadFile("metadatav4-response-task-ec2.json") if err == nil { _, err = res.Write(content) if err != nil { t.Fatal(err) } } } else { content, err := os.ReadFile("metadatav4-response-container-ec2.json") if err == nil { _, err = res.Write(content) if err != nil { t.Fatal(err) } } } })) defer testServer.Close() os.Clearenv() _ = os.Setenv(metadataV4EnvVar, testServer.URL) hostname, err := os.Hostname() assert.NoError(t, err, "Error") attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSECS, semconv.ContainerName(hostname), // We are not running the test in an actual container, // the container id is tested with mocks of the cgroup // file in the unit tests semconv.ContainerID(""), semconv.AWSECSContainerARN("arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"), semconv.AWSECSClusterARN("arn:aws:ecs:us-west-2:111122223333:cluster/default"), semconv.AWSECSLaunchtypeKey.String("ec2"), semconv.AWSECSTaskARN("arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c"), semconv.AWSECSTaskFamily("curltest"), semconv.AWSECSTaskRevision("26"), semconv.AWSLogGroupNames("/ecs/metadata"), semconv.AWSLogGroupARNs("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:*"), semconv.AWSLogStreamNames("ecs/curl/8f03e41243824aea923aca126495f665"), semconv.AWSLogStreamARNs("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/metadata:log-stream:ecs/curl/8f03e41243824aea923aca126495f665"), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) detector := ecs.NewResourceDetector() res, err := detector.Detect(context.Background()) assert.Equal(t, nil, err, "Detector should not fail") assert.Equal(t, expectedResource, res, "Resource returned is incorrect") } // successfully returns resource when process is running on Amazon ECS environment // with Metadata v4 with the Fargate Launch type. func TestDetectV4LaunchTypeFargate(t *testing.T) { testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { if strings.HasSuffix(req.URL.String(), "/task") { content, err := os.ReadFile("metadatav4-response-task-fargate.json") if err == nil { _, err = res.Write(content) if err != nil { panic(err) } } } else { content, err := os.ReadFile("metadatav4-response-container-fargate.json") if err == nil { _, err = res.Write(content) if err != nil { panic(err) } } } })) defer testServer.Close() os.Clearenv() _ = os.Setenv(metadataV4EnvVar, testServer.URL) hostname, err := os.Hostname() assert.NoError(t, err, "Error") attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSECS, semconv.ContainerName(hostname), // We are not running the test in an actual container, // the container id is tested with mocks of the cgroup // file in the unit tests semconv.ContainerID(""), semconv.AWSECSContainerARN("arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1"), semconv.AWSECSClusterARN("arn:aws:ecs:us-west-2:111122223333:cluster/default"), semconv.AWSECSLaunchtypeKey.String("fargate"), semconv.AWSECSTaskARN("arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3"), semconv.AWSECSTaskFamily("curltest"), semconv.AWSECSTaskRevision("3"), semconv.AWSLogGroupNames("/ecs/containerlogs"), semconv.AWSLogGroupARNs("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs:*"), semconv.AWSLogStreamNames("ecs/curl/cd189a933e5849daa93386466019ab50"), semconv.AWSLogStreamARNs("arn:aws:logs:us-west-2:111122223333:log-group:/ecs/containerlogs:log-stream:ecs/curl/cd189a933e5849daa93386466019ab50"), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) detector := ecs.NewResourceDetector() res, err := detector.Detect(context.Background()) assert.Equal(t, nil, err, "Detector should not fail") assert.Equal(t, expectedResource, res, "Resource returned is incorrect") } metadatav4-response-container-ec2.json000066400000000000000000000032711443314701600352760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test{ "DockerId": "ea32192c8553fbff06c9340478a2ff089b2bb5646fb718b4ee206641c9086d66", "Name": "curl", "DockerName": "ecs-curltest-24-curl-cca48e8dcadd97805600", "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", "ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553", "Labels": { "com.amazonaws.ecs.cluster": "default", "com.amazonaws.ecs.container-name": "curl", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/8f03e41243824aea923aca126495f665", "com.amazonaws.ecs.task-definition-family": "curltest", "com.amazonaws.ecs.task-definition-version": "24" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 10, "Memory": 128 }, "CreatedAt": "2020-10-02T00:15:07.620912337Z", "StartedAt": "2020-10-02T00:15:08.062559351Z", "Type": "NORMAL", "LogDriver": "awslogs", "LogOptions": { "awslogs-create-group": "true", "awslogs-group": "/ecs/metadata", "awslogs-region": "us-west-2", "awslogs-stream": "ecs/curl/8f03e41243824aea923aca126495f665" }, "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.0.2.100" ], "AttachmentIndex": 0, "MACAddress": "0e:9e:32:c7:48:85", "IPv4SubnetCIDRBlock": "10.0.2.0/24", "PrivateDNSName": "ip-10-0-2-100.us-west-2.compute.internal", "SubnetGatewayIpv4Address": "10.0.2.1/24" } ] } metadatav4-response-container-fargate.json000066400000000000000000000035341443314701600362400ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test{ "DockerId": "cd189a933e5849daa93386466019ab50-2495160603", "Name": "curl", "DockerName": "curl", "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", "ImageID": "sha256:25f3695bedfb454a50f12d127839a68ad3caf91e451c1da073db34c542c4d2cb", "Labels": { "com.amazonaws.ecs.cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", "com.amazonaws.ecs.container-name": "curl", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/cd189a933e5849daa93386466019ab50", "com.amazonaws.ecs.task-definition-family": "curltest", "com.amazonaws.ecs.task-definition-version": "2" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 10, "Memory": 128 }, "CreatedAt": "2020-10-08T20:09:11.44527186Z", "StartedAt": "2020-10-08T20:09:11.44527186Z", "Type": "NORMAL", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "192.0.2.3" ], "AttachmentIndex": 0, "MACAddress": "0a:de:f6:10:51:e5", "IPv4SubnetCIDRBlock": "192.0.2.0/24", "DomainNameServers": [ "192.0.2.2" ], "DomainNameSearchList": [ "us-west-2.compute.internal" ], "PrivateDNSName": "ip-10-0-0-222.us-west-2.compute.internal", "SubnetGatewayIpv4Address": "192.0.2.0/24" } ], "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1", "LogOptions": { "awslogs-create-group": "true", "awslogs-group": "/ecs/containerlogs", "awslogs-region": "us-west-2", "awslogs-stream": "ecs/curl/cd189a933e5849daa93386466019ab50" }, "LogDriver": "awslogs" }metadatav4-response-task-ec2.json000066400000000000000000000100451443314701600342530ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test{ "Cluster": "default", "TaskARN": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c", "Family": "curltest", "Revision": "26", "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "PullStartedAt": "2020-10-02T00:43:06.202617438Z", "PullStoppedAt": "2020-10-02T00:43:06.31288465Z", "AvailabilityZone": "us-west-2d", "LaunchType": "EC2", "Containers": [ { "DockerId": "598cba581fe3f939459eaba1e071d5c93bb2c49b7d1ba7db6bb19deeb70d8e38", "Name": "~internal~ecs~pause", "DockerName": "ecs-curltest-26-internalecspause-e292d586b6f9dade4a00", "Image": "amazon/amazon-ecs-pause:0.1.0", "ImageID": "", "Labels": { "com.amazonaws.ecs.cluster": "default", "com.amazonaws.ecs.container-name": "~internal~ecs~pause", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c", "com.amazonaws.ecs.task-definition-family": "curltest", "com.amazonaws.ecs.task-definition-version": "26" }, "DesiredStatus": "RESOURCES_PROVISIONED", "KnownStatus": "RESOURCES_PROVISIONED", "Limits": { "CPU": 0, "Memory": 0 }, "CreatedAt": "2020-10-02T00:43:05.602352471Z", "StartedAt": "2020-10-02T00:43:06.076707576Z", "Type": "CNI_PAUSE", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.0.2.61" ], "AttachmentIndex": 0, "MACAddress": "0e:10:e2:01:bd:91", "IPv4SubnetCIDRBlock": "10.0.2.0/24", "PrivateDNSName": "ip-10-0-2-61.us-west-2.compute.internal", "SubnetGatewayIpv4Address": "10.0.2.1/24" } ] }, { "DockerId": "ee08638adaaf009d78c248913f629e38299471d45fe7dc944d1039077e3424ca", "Name": "curl", "DockerName": "ecs-curltest-26-curl-a0e7dba5aca6d8cb2e00", "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", "ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553", "Labels": { "com.amazonaws.ecs.cluster": "default", "com.amazonaws.ecs.container-name": "curl", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c", "com.amazonaws.ecs.task-definition-family": "curltest", "com.amazonaws.ecs.task-definition-version": "26" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 10, "Memory": 128 }, "CreatedAt": "2020-10-02T00:43:06.326590752Z", "StartedAt": "2020-10-02T00:43:06.767535449Z", "Type": "NORMAL", "LogDriver": "awslogs", "LogOptions": { "awslogs-create-group": "true", "awslogs-group": "/ecs/metadata", "awslogs-region": "us-west-2", "awslogs-stream": "ecs/curl/158d1c8083dd49d6b527399fd6414f5c" }, "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/abb51bdd-11b4-467f-8f6c-adcfe1fe059d", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "10.0.2.61" ], "AttachmentIndex": 0, "MACAddress": "0e:10:e2:01:bd:91", "IPv4SubnetCIDRBlock": "10.0.2.0/24", "PrivateDNSName": "ip-10-0-2-61.us-west-2.compute.internal", "SubnetGatewayIpv4Address": "10.0.2.1/24" } ] } ] } metadatav4-response-task-fargate.json000066400000000000000000000062711443314701600352210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/test{ "Cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", "TaskARN": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", "Family": "curltest", "Revision": "3", "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 0.25, "Memory": 512 }, "PullStartedAt": "2020-10-08T20:47:16.053330955Z", "PullStoppedAt": "2020-10-08T20:47:19.592684631Z", "AvailabilityZone": "us-west-2a", "Containers": [ { "DockerId": "e9028f8d5d8e4f258373e7b93ce9a3c3-2495160603", "Name": "curl", "DockerName": "curl", "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", "ImageID": "sha256:25f3695bedfb454a50f12d127839a68ad3caf91e451c1da073db34c542c4d2cb", "Labels": { "com.amazonaws.ecs.cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", "com.amazonaws.ecs.container-name": "curl", "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", "com.amazonaws.ecs.task-definition-family": "curltest", "com.amazonaws.ecs.task-definition-version": "3" }, "DesiredStatus": "RUNNING", "KnownStatus": "RUNNING", "Limits": { "CPU": 10, "Memory": 128 }, "CreatedAt": "2020-10-08T20:47:20.567813946Z", "StartedAt": "2020-10-08T20:47:20.567813946Z", "Type": "NORMAL", "Networks": [ { "NetworkMode": "awsvpc", "IPv4Addresses": [ "192.0.2.3" ], "IPv6Addresses": [ "2001:dB8:10b:1a00:32bf:a372:d80f:e958" ], "AttachmentIndex": 0, "MACAddress": "02:b7:20:19:72:39", "IPv4SubnetCIDRBlock": "192.0.2.0/24", "IPv6SubnetCIDRBlock": "2600:1f13:10b:1a00::/64", "DomainNameServers": [ "192.0.2.2" ], "DomainNameSearchList": [ "us-west-2.compute.internal" ], "PrivateDNSName": "ip-172-31-30-173.us-west-2.compute.internal", "SubnetGatewayIpv4Address": "192.0.2.0/24" } ], "ClockDrift": { "ClockErrorBound": 0.5458234999999999, "ReferenceTimestamp": "2021-09-07T16:57:44Z", "ClockSynchronizationStatus": "SYNCHRONIZED" }, "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/1bdcca8b-f905-4ee6-885c-4064cb70f6e6", "LogOptions": { "awslogs-create-group": "true", "awslogs-group": "/ecs/containerlogs", "awslogs-region": "us-west-2", "awslogs-stream": "ecs/curl/e9028f8d5d8e4f258373e7b93ce9a3c3" }, "LogDriver": "awslogs" } ], "LaunchType": "FARGATE" }open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/ecs/version.go000066400000000000000000000017771443314701600272130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ecs // import "go.opentelemetry.io/contrib/detectors/aws/ecs" // Version is the current release version of the ECS resource detector. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/000077500000000000000000000000001443314701600251735ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/detector.go000066400000000000000000000145301443314701600273360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package eks // import "go.opentelemetry.io/contrib/detectors/aws/eks" import ( "context" "fmt" "os" "regexp" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const ( k8sTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" k8sCertPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" authConfigmapNS = "kube-system" authConfigmapName = "aws-auth" cwConfigmapNS = "amazon-cloudwatch" cwConfigmapName = "cluster-info" defaultCgroupPath = "/proc/self/cgroup" containerIDLength = 64 ) // detectorUtils is used for testing the resourceDetector by abstracting functions that rely on external systems. type detectorUtils interface { fileExists(filename string) bool getConfigMap(ctx context.Context, namespace string, name string) (map[string]string, error) getContainerID() (string, error) } // This struct will implement the detectorUtils interface. type eksDetectorUtils struct { clientset *kubernetes.Clientset } // resourceDetector for detecting resources running on Amazon EKS. type resourceDetector struct { utils detectorUtils err error } // Compile time assertion that resourceDetector implements the resource.Detector interface. var _ resource.Detector = (*resourceDetector)(nil) // Compile time assertion that eksDetectorUtils implements the detectorUtils interface. var _ detectorUtils = (*eksDetectorUtils)(nil) // NewResourceDetector returns a resource detector that will detect AWS EKS resources. func NewResourceDetector() resource.Detector { utils, err := newK8sDetectorUtils() return &resourceDetector{utils: utils, err: err} } // Detect returns a Resource describing the Amazon EKS environment being run in. func (detector *resourceDetector) Detect(ctx context.Context) (*resource.Resource, error) { if detector.err != nil { return nil, detector.err } isEks, err := isEKS(ctx, detector.utils) if err != nil { return nil, err } // Return empty resource object if not running in EKS if !isEks { return resource.Empty(), nil } // Create variable to hold resource attributes attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSEKS, } // Get clusterName and append to attributes clusterName, err := getClusterName(ctx, detector.utils) if err != nil { return nil, err } if clusterName != "" { attributes = append(attributes, semconv.K8SClusterName(clusterName)) } // Get containerID and append to attributes containerID, err := detector.utils.getContainerID() if err != nil { return nil, err } if containerID != "" { attributes = append(attributes, semconv.ContainerID(containerID)) } // Return new resource object with clusterName and containerID as attributes return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil } // isEKS checks if the current environment is running in EKS. func isEKS(ctx context.Context, utils detectorUtils) (bool, error) { if !isK8s(utils) { return false, nil } // Make HTTP GET request awsAuth, err := utils.getConfigMap(ctx, authConfigmapNS, authConfigmapName) if err != nil { return false, fmt.Errorf("isEks() error retrieving auth configmap: %w", err) } return awsAuth != nil, nil } // newK8sDetectorUtils creates the Kubernetes clientset. func newK8sDetectorUtils() (*eksDetectorUtils, error) { // Get cluster configuration confs, err := rest.InClusterConfig() if err != nil { return nil, fmt.Errorf("failed to create config: %w", err) } // Create clientset using generated configuration clientset, err := kubernetes.NewForConfig(confs) if err != nil { return nil, fmt.Errorf("failed to create clientset for Kubernetes client") } return &eksDetectorUtils{clientset: clientset}, nil } // isK8s checks if the current environment is running in a Kubernetes environment. func isK8s(utils detectorUtils) bool { return utils.fileExists(k8sTokenPath) && utils.fileExists(k8sCertPath) } // fileExists checks if a file with a given filename exists. func (eksUtils eksDetectorUtils) fileExists(filename string) bool { info, err := os.Stat(filename) return err == nil && !info.IsDir() } // getConfigMap retrieves the configuration map from the k8s API. func (eksUtils eksDetectorUtils) getConfigMap(ctx context.Context, namespace string, name string) (map[string]string, error) { cm, err := eksUtils.clientset.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to retrieve ConfigMap %s/%s: %w", namespace, name, err) } return cm.Data, nil } // getClusterName retrieves the clusterName resource attribute. func getClusterName(ctx context.Context, utils detectorUtils) (string, error) { resp, err := utils.getConfigMap(ctx, cwConfigmapNS, cwConfigmapName) if err != nil { return "", fmt.Errorf("getClusterName() error: %w", err) } return resp["cluster.name"], nil } // getContainerID returns the containerID if currently running within a container. func (eksUtils eksDetectorUtils) getContainerID() (string, error) { fileData, err := os.ReadFile(defaultCgroupPath) if err != nil { return "", fmt.Errorf("getContainerID() error: cannot read file with path %s: %w", defaultCgroupPath, err) } // is this going to stop working with 1.20 when Docker is deprecated? r, err := regexp.Compile(`^.*/docker/(.+)$`) if err != nil { return "", err } // Retrieve containerID from file splitData := strings.Split(strings.TrimSpace(string(fileData)), "\n") for _, str := range splitData { if r.MatchString(str) { return str[len(str)-containerIDLength:], nil } } return "", fmt.Errorf("getContainerID() error: cannot read containerID from file %s", defaultCgroupPath) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/detector_test.go000066400000000000000000000064331443314701600304000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package eks import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) type MockDetectorUtils struct { mock.Mock } // Mock function for fileExists(). func (detectorUtils *MockDetectorUtils) fileExists(filename string) bool { args := detectorUtils.Called(filename) return args.Bool(0) } // Mock function for getConfigMap(). func (detectorUtils *MockDetectorUtils) getConfigMap(_ context.Context, namespace string, name string) (map[string]string, error) { args := detectorUtils.Called(namespace, name) return args.Get(0).(map[string]string), args.Error(1) } // Mock function for getContainerID(). func (detectorUtils *MockDetectorUtils) getContainerID() (string, error) { args := detectorUtils.Called() return args.String(0), args.Error(1) } // Tests EKS resource detector running in EKS environment. func TestEks(t *testing.T) { detectorUtils := new(MockDetectorUtils) // Mock functions and set expectations detectorUtils.On("fileExists", k8sTokenPath).Return(true) detectorUtils.On("fileExists", k8sCertPath).Return(true) detectorUtils.On("getConfigMap", authConfigmapNS, authConfigmapName).Return(map[string]string{"not": "nil"}, nil) detectorUtils.On("getConfigMap", cwConfigmapNS, cwConfigmapName).Return(map[string]string{"cluster.name": "my-cluster"}, nil) detectorUtils.On("getContainerID").Return("0123456789A", nil) // Expected resource object eksResourceLabels := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudPlatformAWSEKS, semconv.K8SClusterName("my-cluster"), semconv.ContainerID("0123456789A"), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, eksResourceLabels...) // Call EKS Resource detector to detect resources eksResourceDetector := resourceDetector{utils: detectorUtils} resourceObj, err := eksResourceDetector.Detect(context.Background()) require.NoError(t, err) assert.Equal(t, expectedResource, resourceObj, "Resource object returned is incorrect") detectorUtils.AssertExpectations(t) } // Tests EKS resource detector not running in EKS environment. func TestNotEKS(t *testing.T) { detectorUtils := new(MockDetectorUtils) k8sTokenPath := "/var/run/secrets/kubernetes.io/serviceaccount/token" // Mock functions and set expectations detectorUtils.On("fileExists", k8sTokenPath).Return(false) detector := resourceDetector{utils: detectorUtils} r, err := detector.Detect(context.Background()) require.NoError(t, err) assert.Equal(t, resource.Empty(), r, "Resource object should be empty") detectorUtils.AssertExpectations(t) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/go.mod000066400000000000000000000043441443314701600263060ustar00rootroot00000000000000module go.opentelemetry.io/contrib/detectors/aws/eks go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 k8s.io/apimachinery v0.27.2 k8s.io/client-go v0.27.2 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.27.2 // indirect k8s.io/klog/v2 v2.90.1 //indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/go.sum000066400000000000000000001364661443314701600263460ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/eks/version.go000066400000000000000000000017771443314701600272230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package eks // import "go.opentelemetry.io/contrib/detectors/aws/eks" // Version is the current release version of the EKS resource detector. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/000077500000000000000000000000001443314701600256315ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/README.md000066400000000000000000000046031443314701600271130ustar00rootroot00000000000000# OpenTelemetry AWS Lambda Resource Detector for Golang [![Go Reference][goref-image]][goref-url] [![Apache License][license-image]][license-url] This module detects resource attributes available in AWS Lambda. ## Installation ```bash go get -u go.opentelemetry.io/contrib/detectors/aws/lambda ``` ## Usage Create a sample Lambda Go application such as below. ```go package main import ( "github.com/aws/aws-lambda-go/lambda" sdktrace "go.opencensus.io/otel/sdk/trace" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" ) func main() { detector := lambdadetector.NewResourceDetector() res, err := detector.Detect(context.Background()) if err != nil { fmt.Printf("failed to detect lambda resources: %v\n", err) } tp := sdktrace.NewTracerProvider( sdktrace.WithResource(res), ) lambda.Start() } ``` Now your `TracerProvider` will have the following resource attributes and attach them to new spans: | Resource Attribute | Example Value | | --- | --- | | `cloud.provider` | aws |`cloud.region` | us-east-1 |`faas.name` | MyLambdaFunction |`faas.version` | $LATEST |`faas.instance` | 2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de |`faas.max_memory`| 128 Of note, `faas.id` and `cloud.account.id` are not set by the Lambda resource detector because they are not available outside a Lambda invocation. For this reason, when using the AWS Lambda Instrumentation these attributes are set as additional span attributes. ## Useful links - For more on FaaS attribute conventions, visit - For more information on OpenTelemetry, visit: - For more about OpenTelemetry Go: - For help or feedback on this project, join us in [GitHub Discussions][discussions-url] ## License Apache 2.0 - See [LICENSE][license-url] for more information. [license-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE [license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat [goref-image]: https://pkg.go.dev/badge/go.opentelemetry.io/contrib/detectors/aws/lambda.svg [goref-url]: https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/aws/lambda [discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/detector.go000066400000000000000000000055531443314701600300010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lambda // import "go.opentelemetry.io/contrib/detectors/aws/lambda" import ( "context" "errors" "os" "strconv" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // For a complete list of reserved environment variables in Lambda, see: // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html const ( lambdaFunctionNameEnvVar = "AWS_LAMBDA_FUNCTION_NAME" awsRegionEnvVar = "AWS_REGION" lambdaFunctionVersionEnvVar = "AWS_LAMBDA_FUNCTION_VERSION" lambdaLogStreamNameEnvVar = "AWS_LAMBDA_LOG_STREAM_NAME" lambdaMemoryLimitEnvVar = "AWS_LAMBDA_FUNCTION_MEMORY_SIZE" ) var ( empty = resource.Empty() errNotOnLambda = errors.New("process is not on Lambda, cannot detect environment variables from Lambda") ) // resource detector collects resource information from Lambda environment. type resourceDetector struct{} // compile time assertion that resource detector implements the resource.Detector interface. var _ resource.Detector = (*resourceDetector)(nil) // NewResourceDetector returns a resource detector that will detect AWS Lambda resources. func NewResourceDetector() resource.Detector { return &resourceDetector{} } // Detect collects resource attributes available when running on lambda. func (detector *resourceDetector) Detect(context.Context) (*resource.Resource, error) { // Lambda resources come from ENV lambdaName := os.Getenv(lambdaFunctionNameEnvVar) if len(lambdaName) == 0 { return empty, errNotOnLambda } awsRegion := os.Getenv(awsRegionEnvVar) functionVersion := os.Getenv(lambdaFunctionVersionEnvVar) // The instance attributes corresponds to the log stream name for AWS lambda, // see the FaaS resource specification for more details. instance := os.Getenv(lambdaLogStreamNameEnvVar) attrs := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudRegion(awsRegion), semconv.FaaSInstance(instance), semconv.FaaSName(lambdaName), semconv.FaaSVersion(functionVersion), } maxMemoryStr := os.Getenv(lambdaMemoryLimitEnvVar) maxMemory, err := strconv.Atoi(maxMemoryStr) if err == nil { attrs = append(attrs, semconv.FaaSMaxMemory(maxMemory)) } return resource.NewWithAttributes(semconv.SchemaURL, attrs...), nil } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/detector_test.go000066400000000000000000000041301443314701600310260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lambda import ( "context" "os" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // successfully return resource when process is running on Amazon Lambda environment. func TestDetectSuccess(t *testing.T) { os.Clearenv() _ = os.Setenv(lambdaFunctionNameEnvVar, "testFunction") _ = os.Setenv(awsRegionEnvVar, "us-texas-1") _ = os.Setenv(lambdaFunctionVersionEnvVar, "$LATEST") _ = os.Setenv(lambdaLogStreamNameEnvVar, "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc") _ = os.Setenv(lambdaMemoryLimitEnvVar, "128") attributes := []attribute.KeyValue{ semconv.CloudProviderAWS, semconv.CloudRegion("us-texas-1"), semconv.FaaSName("testFunction"), semconv.FaaSVersion("$LATEST"), semconv.FaaSInstance("2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"), semconv.FaaSMaxMemory(128), } expectedResource := resource.NewWithAttributes(semconv.SchemaURL, attributes...) detector := resourceDetector{} res, err := detector.Detect(context.Background()) assert.Nil(t, err, "Detector unexpectedly returned error") assert.Equal(t, expectedResource, res, "Resource returned is incorrect") } // return empty resource when not running on lambda. func TestReturnsIfNoEnvVars(t *testing.T) { os.Clearenv() detector := resourceDetector{} res, err := detector.Detect(context.Background()) assert.Equal(t, errNotOnLambda, err) assert.Equal(t, 0, len(res.Attributes())) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/go.mod000066400000000000000000000010631443314701600267370ustar00rootroot00000000000000module go.opentelemetry.io/contrib/detectors/aws/lambda go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/detectors/aws/lambda/go.sum000066400000000000000000000042761443314701600267750ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/000077500000000000000000000000001443314701600243705ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/README.md000066400000000000000000000027641443314701600256600ustar00rootroot00000000000000# GCP Resource detector The GCP resource detector supports detecting resources on: * Google Compute Engine (GCE) * Google Kubernetes Engine (GKE) * Google App Engine (GAE) * Cloud Run * Cloud Functions ## Usage ```golang ctx := context.Background() // Detect your resources res, err := resource.New(ctx, // Use the GCP resource detector! resource.WithDetectors(gcp.NewDetector()), // Keep the default detectors resource.WithTelemetrySDK(), // Add your own custom attributes to identify your application resource.WithAttributes( semconv.ServiceNameKey.String("my-application"), semconv.ServiceNamespaceKey.String("my-company-frontend-team"), ), ) if err != nil { // Handle err } // Use the resource in your tracerprovider (or meterprovider) tp := trace.NewTracerProvider( // ... other options trace.WithResource(res), ) ``` ## Setting Kubernetes attributes Previous iterations of GCP resource detection attempted to detect `container.name`, `k8s.pod.name` and `k8s.namespace.name`. When using this detector, you should use this in your Pod Spec to set these using `OTEL_RESOURCE_ATTRIBUTES`: ```yaml env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: NAMESPACE_NAME valueFrom: fieldRef: fieldPath: metadata.namespace - name: CONTAINER_NAME value: my-container-name - name: OTEL_RESOURCE_ATTRIBUTES value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/cloud-function.go000066400000000000000000000040071443314701600276510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "os" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const ( gcpFunctionNameKey = "K_SERVICE" ) // NewCloudFunction will return a GCP Cloud Function resource detector. // Deprecated: Use gcp.NewDetector() instead, which sets the same resource attributes. func NewCloudFunction() resource.Detector { return &cloudFunction{ cloudRun: NewCloudRun(), } } // cloudFunction collects resource information of GCP Cloud Function. type cloudFunction struct { cloudRun *CloudRun } // Detect detects associated resources when running in GCP Cloud Function. func (f *cloudFunction) Detect(ctx context.Context) (*resource.Resource, error) { functionName, ok := f.googleCloudFunctionName() if !ok { return nil, nil } projectID, err := f.cloudRun.mc.ProjectID() if err != nil { return nil, err } region, err := f.cloudRun.cloudRegion(ctx) if err != nil { return nil, err } attributes := []attribute.KeyValue{ semconv.CloudProviderGCP, semconv.CloudPlatformGCPCloudFunctions, semconv.FaaSName(functionName), semconv.CloudAccountID(projectID), semconv.CloudRegion(region), } return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil } func (f *cloudFunction) googleCloudFunctionName() (string, bool) { return os.LookupEnv(gcpFunctionNameKey) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/cloud-function_test.go000066400000000000000000000076421443314701600307200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp import ( "context" "errors" "os" "testing" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) var ( errTest = errors.New("testError") ) const ( projectIDValue = "some-projectID" regionValue = "some-region" functionName = "sample-function" ) type metaDataClientImpl struct { projectID func() (string, error) get func(string) (string, error) instanceID func() (string, error) } func (mock *metaDataClientImpl) ProjectID() (string, error) { if mock.projectID != nil { return mock.projectID() } return "", nil } func (mock *metaDataClientImpl) Get(key string) (string, error) { if mock.get != nil { return mock.get(key) } return "", nil } func (mock *metaDataClientImpl) InstanceID() (string, error) { if mock.instanceID != nil { return mock.instanceID() } return "", nil } type want struct { res *resource.Resource err error } func TestCloudFunctionDetect(t *testing.T) { oldValue, ok := os.LookupEnv(gcpFunctionNameKey) if !ok { err := os.Setenv(gcpFunctionNameKey, functionName) if err != nil { t.Error("unable to set environment variable ", err) } } defer func() { if !ok { _ = os.Unsetenv(gcpFunctionNameKey) } else { _ = os.Setenv(gcpFunctionNameKey, oldValue) } }() tests := []struct { name string cr *CloudRun expected want }{ { name: "error in reading ProjectID", cr: &CloudRun{ mc: &metaDataClientImpl{ projectID: func() (string, error) { return "", errTest }, }, }, expected: want{ res: nil, err: errTest, }, }, { name: "error in reading region", cr: &CloudRun{ mc: &metaDataClientImpl{ get: func(key string) (string, error) { return "", errTest }, }, }, expected: want{ res: nil, err: errTest, }, }, { name: "success", cr: &CloudRun{ mc: &metaDataClientImpl{ projectID: func() (string, error) { return projectIDValue, nil }, get: func(key string) (string, error) { return regionValue, nil }, }, }, expected: want{ res: resource.NewSchemaless([]attribute.KeyValue{ semconv.CloudProviderGCP, semconv.CloudPlatformGCPCloudFunctions, semconv.FaaSName(functionName), semconv.CloudAccountID(projectIDValue), semconv.CloudRegion(regionValue), }...), err: nil, }, }, } for _, test := range tests { detector := cloudFunction{ cloudRun: test.cr, } res, err := detector.Detect(context.Background()) if err != test.expected.err { t.Fatalf("got unexpected failure: %v", err) } else if diff := cmp.Diff(test.expected.res, res); diff != "" { t.Errorf("detected resource differ from expected (-want, +got)\n%s", diff) } } } func TestNotOnCloudFunction(t *testing.T) { oldValue, ok := os.LookupEnv(gcpFunctionNameKey) if ok { _ = os.Unsetenv(gcpFunctionNameKey) } defer func() { if ok { _ = os.Setenv(gcpFunctionNameKey, oldValue) } }() detector := NewCloudFunction() res, err := detector.Detect(context.Background()) if err != nil { t.Errorf("expected cloud function detector to return error as nil, but returned %v", err) } else if res != nil { t.Errorf("expected cloud function detector to return resource as nil, but returned %v", res) } } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/cloud-run.go000066400000000000000000000077241443314701600266410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "fmt" "os" "strings" "cloud.google.com/go/compute/metadata" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const serviceNamespace = "cloud-run-managed" // The minimal list of metadata.Client methods we use. Use an interface so we // can replace it with a fake implementation in the unit test. type metadataClient interface { ProjectID() (string, error) Get(string) (string, error) InstanceID() (string, error) } // CloudRun collects resource information of Cloud Run instance. // Deprecated: Use gcp.NewDetector() instead. Note that it sets faas.* resource attributes instead of service.* attributes. type CloudRun struct { mc metadataClient onGCE func() bool getenv func(string) string } // compile time assertion that CloudRun implements the resource.Detector // interface. var _ resource.Detector = (*CloudRun)(nil) // NewCloudRun creates a CloudRun detector. // Deprecated: Use gcp.NewDetector() instead. Note that it sets faas.* resource attributes instead of service.* attributes. func NewCloudRun() *CloudRun { return &CloudRun{ mc: metadata.NewClient(nil), onGCE: metadata.OnGCE, getenv: os.Getenv, } } func (c *CloudRun) cloudRegion(ctx context.Context) (string, error) { region, err := c.mc.Get("instance/region") if err != nil { return "", err } // Region from the metadata server is in the format /projects/123/regions/r. // https://cloud.google.com/run/docs/reference/container-contract#metadata-server return region[strings.LastIndex(region, "/")+1:], nil } // Detect detects associated resources when running on Cloud Run hosts. // NOTE: the service.namespace attribute is currently hardcoded to be // "cloud-run-managed". This may change in the future, please do not rely on // this behavior yet. func (c *CloudRun) Detect(ctx context.Context) (*resource.Resource, error) { // .OnGCE is actually testing whether the metadata server is available. // Metadata server is supported on Cloud Run. if !c.onGCE() { return nil, nil } attributes := []attribute.KeyValue{ semconv.CloudProviderGCP, semconv.ServiceNamespace(serviceNamespace), } var errInfo []string if projectID, err := c.mc.ProjectID(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if projectID != "" { attributes = append(attributes, semconv.CloudAccountID(projectID)) } if region, err := c.cloudRegion(ctx); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if region != "" { attributes = append(attributes, semconv.CloudRegion(region)) } if instanceID, err := c.mc.InstanceID(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if instanceID != "" { attributes = append(attributes, semconv.ServiceInstanceID(instanceID)) } // Part of Cloud Run container runtime contract. // See https://cloud.google.com/run/docs/reference/container-contract if service := c.getenv("K_SERVICE"); service == "" { errInfo = append(errInfo, "envvar K_SERVICE contains empty string.") } else { attributes = append(attributes, semconv.ServiceName(service)) } res := resource.NewWithAttributes(semconv.SchemaURL, attributes...) var aggregatedErr error if len(errInfo) > 0 { aggregatedErr = fmt.Errorf("detecting Cloud Run resources: %s", errInfo) } return res, aggregatedErr } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/cloud-run_test.go000066400000000000000000000103151443314701600276660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp import ( "context" "fmt" "testing" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" ) var ( notOnGCE = func() bool { return false } onGCE = func() bool { return true } ) func getenv(m map[string]string) func(string) string { return func(s string) string { if m == nil { return "" } return m[s] } } type client struct { m map[string]string } func setupForTest(c *CloudRun, mc metadataClient, ongce func() bool, getenv func(string) string) { c.mc = mc c.onGCE = ongce c.getenv = getenv } func (c *client) Get(s string) (string, error) { got, ok := c.m[s] if !ok { return "", fmt.Errorf("%q do not exist", s) } else if got == "" { return "", fmt.Errorf("%q is empty", s) } return got, nil } func (c *client) InstanceID() (string, error) { return c.Get("instance/id") } func (c *client) ProjectID() (string, error) { return c.Get("project/project-id") } var _ metadataClient = (*client)(nil) func TestCloudRunDetectorNotOnGCE(t *testing.T) { ctx := context.Background() c := NewCloudRun() setupForTest(c, nil, notOnGCE, getenv(nil)) if res, err := c.Detect(ctx); res != nil || err != nil { t.Errorf("Expect c.Detect(ctx) to return (nil, nil), got (%v, %v)", res, err) } } func TestCloudRunDetectorExpectSuccess(t *testing.T) { ctx := context.Background() metadata := map[string]string{ "project/project-id": "foo", "instance/id": "bar", "instance/region": "/projects/123/regions/utopia", } envvars := map[string]string{ "K_SERVICE": "x-service", } want, err := resource.New( ctx, resource.WithAttributes( attribute.String("cloud.account.id", "foo"), attribute.String("cloud.provider", "gcp"), attribute.String("cloud.region", "utopia"), attribute.String("service.instance.id", "bar"), attribute.String("service.name", "x-service"), attribute.String("service.namespace", "cloud-run-managed"), ), ) if err != nil { t.Fatalf("failed to create a resource: %v", err) } c := NewCloudRun() setupForTest(c, &client{m: metadata}, onGCE, getenv(envvars)) if res, err := c.Detect(ctx); err != nil { t.Fatalf("got unexpected failure: %v", err) } else if diff := cmp.Diff(want, res); diff != "" { t.Errorf("detected resource differ from expected (-want, +got)\n%s", diff) } } func TestCloudRunDetectorExpectFail(t *testing.T) { ctx := context.Background() tests := []struct { name string metadata map[string]string envvars map[string]string }{ { name: "Missing ProjectID", metadata: map[string]string{ "instance/id": "bar", "instance/region": "utopia", }, envvars: map[string]string{ "K_SERVICE": "x-service", }, }, { name: "Missing InstanceID", metadata: map[string]string{ "project/project-id": "foo", "instance/region": "utopia", }, envvars: map[string]string{ "K_SERVICE": "x-service", }, }, { name: "Missing Region", metadata: map[string]string{ "project/project-id": "foo", "instance/id": "bar", }, envvars: map[string]string{ "K_SERVICE": "x-service", }, }, { name: "Missing K_SERVICE envvar", metadata: map[string]string{ "project/project-id": "foo", "instance/id": "bar", "instance/region": "utopia", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { c := NewCloudRun() setupForTest(c, &client{m: test.metadata}, onGCE, getenv(test.envvars)) if res, err := c.Detect(ctx); err == nil { t.Errorf("Expect c.Detect(ctx) to return error, got nil (resource: %v)", res) } else { t.Logf("err: %v", err) } }) } } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/detector.go000066400000000000000000000121441443314701600265320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "fmt" "cloud.google.com/go/compute/metadata" "github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // NewDetector returns a resource detector which detects resource attributes on: // * Google Compute Engine (GCE). // * Google Kubernetes Engine (GKE). // * Google App Engine (GAE). // * Cloud Run. // * Cloud Functions. func NewDetector() resource.Detector { return &detector{detector: gcp.NewDetector()} } type detector struct { detector gcpDetector } // Detect detects associated resources when running on GCE, GKE, GAE, // Cloud Run, and Cloud functions. func (d *detector) Detect(ctx context.Context) (*resource.Resource, error) { if !metadata.OnGCE() { return nil, nil } b := &resourceBuilder{} b.attrs = append(b.attrs, semconv.CloudProviderGCP) b.add(semconv.CloudAccountIDKey, d.detector.ProjectID) switch d.detector.CloudPlatform() { case gcp.GKE: b.attrs = append(b.attrs, semconv.CloudPlatformGCPKubernetesEngine) b.addZoneOrRegion(d.detector.GKEAvailabilityZoneOrRegion) b.add(semconv.K8SClusterNameKey, d.detector.GKEClusterName) b.add(semconv.HostIDKey, d.detector.GKEHostID) case gcp.CloudRun: b.attrs = append(b.attrs, semconv.CloudPlatformGCPCloudRun) b.add(semconv.FaaSNameKey, d.detector.FaaSName) b.add(semconv.FaaSVersionKey, d.detector.FaaSVersion) b.add(semconv.FaaSIDKey, d.detector.FaaSID) b.add(semconv.CloudRegionKey, d.detector.FaaSCloudRegion) case gcp.CloudFunctions: b.attrs = append(b.attrs, semconv.CloudPlatformGCPCloudFunctions) b.add(semconv.FaaSNameKey, d.detector.FaaSName) b.add(semconv.FaaSVersionKey, d.detector.FaaSVersion) b.add(semconv.FaaSIDKey, d.detector.FaaSID) b.add(semconv.CloudRegionKey, d.detector.FaaSCloudRegion) case gcp.AppEngineFlex: b.attrs = append(b.attrs, semconv.CloudPlatformGCPAppEngine) b.addZoneAndRegion(d.detector.AppEngineFlexAvailabilityZoneAndRegion) b.add(semconv.FaaSNameKey, d.detector.AppEngineServiceName) b.add(semconv.FaaSVersionKey, d.detector.AppEngineServiceVersion) b.add(semconv.FaaSIDKey, d.detector.AppEngineServiceInstance) case gcp.AppEngineStandard: b.attrs = append(b.attrs, semconv.CloudPlatformGCPAppEngine) b.add(semconv.CloudAvailabilityZoneKey, d.detector.AppEngineStandardAvailabilityZone) b.add(semconv.CloudRegionKey, d.detector.AppEngineStandardCloudRegion) b.add(semconv.FaaSNameKey, d.detector.AppEngineServiceName) b.add(semconv.FaaSVersionKey, d.detector.AppEngineServiceVersion) b.add(semconv.FaaSIDKey, d.detector.AppEngineServiceInstance) case gcp.GCE: b.attrs = append(b.attrs, semconv.CloudPlatformGCPComputeEngine) b.addZoneAndRegion(d.detector.GCEAvailabilityZoneAndRegion) b.add(semconv.HostTypeKey, d.detector.GCEHostType) b.add(semconv.HostIDKey, d.detector.GCEHostID) b.add(semconv.HostNameKey, d.detector.GCEHostName) default: // We don't support this platform yet, so just return with what we have } return b.build() } // resourceBuilder simplifies constructing resources using GCP detection // library functions. type resourceBuilder struct { errs []error attrs []attribute.KeyValue } func (r *resourceBuilder) add(key attribute.Key, detect func() (string, error)) { if v, err := detect(); err == nil { r.attrs = append(r.attrs, key.String(v)) } else { r.errs = append(r.errs, err) } } // zoneAndRegion functions are expected to return zone, region, err. func (r *resourceBuilder) addZoneAndRegion(detect func() (string, string, error)) { if zone, region, err := detect(); err == nil { r.attrs = append(r.attrs, semconv.CloudAvailabilityZone(zone)) r.attrs = append(r.attrs, semconv.CloudRegion(region)) } else { r.errs = append(r.errs, err) } } func (r *resourceBuilder) addZoneOrRegion(detect func() (string, gcp.LocationType, error)) { if v, locType, err := detect(); err == nil { switch locType { case gcp.Zone: r.attrs = append(r.attrs, semconv.CloudAvailabilityZone(v)) case gcp.Region: r.attrs = append(r.attrs, semconv.CloudRegion(v)) default: r.errs = append(r.errs, fmt.Errorf("location must be zone or region. Got %v", locType)) } } else { r.errs = append(r.errs, err) } } func (r *resourceBuilder) build() (*resource.Resource, error) { var err error if len(r.errs) > 0 { err = fmt.Errorf("%w: %s", resource.ErrPartialResource, r.errs) } return resource.NewWithAttributes(semconv.SchemaURL, r.attrs...), err } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/detector_test.go000066400000000000000000000250751443314701600276000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "fmt" "os" "testing" "github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func TestDetect(t *testing.T) { // Set this before all tests to ensure metadata.onGCE() returns true err := os.Setenv("GCE_METADATA_HOST", "169.254.169.254") assert.NoError(t, err) for _, tc := range []struct { desc string detector resource.Detector expectErr bool expectedResource *resource.Resource }{ { desc: "zonal GKE cluster", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.GKE, gkeHostID: "1472385723456792345", gkeClusterName: "my-cluster", gkeAvailabilityZone: "us-central1-c", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPKubernetesEngine, semconv.K8SClusterName("my-cluster"), semconv.CloudAvailabilityZone("us-central1-c"), semconv.HostID("1472385723456792345"), ), }, { desc: "regional GKE cluster", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.GKE, gkeHostID: "1472385723456792345", gkeClusterName: "my-cluster", gkeRegion: "us-central1", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPKubernetesEngine, semconv.K8SClusterName("my-cluster"), semconv.CloudRegion("us-central1"), semconv.HostID("1472385723456792345"), ), }, { desc: "GCE", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.GCE, gceHostID: "1472385723456792345", gceHostName: "my-gke-node-1234", gceHostType: "n1-standard1", gceAvailabilityZone: "us-central1-c", gceRegion: "us-central1", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPComputeEngine, semconv.HostID("1472385723456792345"), semconv.HostName("my-gke-node-1234"), semconv.HostType("n1-standard1"), semconv.CloudRegion("us-central1"), semconv.CloudAvailabilityZone("us-central1-c"), ), }, { desc: "Cloud Run", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.CloudRun, faaSID: "1472385723456792345", faaSCloudRegion: "us-central1", faaSName: "my-service", faaSVersion: "123456", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPCloudRun, semconv.CloudRegion("us-central1"), semconv.FaaSName("my-service"), semconv.FaaSVersion("123456"), semconv.FaaSID("1472385723456792345"), ), }, { desc: "Cloud Functions", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.CloudFunctions, faaSID: "1472385723456792345", faaSCloudRegion: "us-central1", faaSName: "my-service", faaSVersion: "123456", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPCloudFunctions, semconv.CloudRegion("us-central1"), semconv.FaaSName("my-service"), semconv.FaaSVersion("123456"), semconv.FaaSID("1472385723456792345"), ), }, { desc: "App Engine Flex", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.AppEngineFlex, appEngineServiceInstance: "1472385723456792345", appEngineAvailabilityZone: "us-central1-c", appEngineRegion: "us-central1", appEngineServiceName: "my-service", appEngineServiceVersion: "123456", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPAppEngine, semconv.CloudRegion("us-central1"), semconv.CloudAvailabilityZone("us-central1-c"), semconv.FaaSName("my-service"), semconv.FaaSVersion("123456"), semconv.FaaSID("1472385723456792345"), ), }, { desc: "App Engine Standard", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.AppEngineStandard, appEngineServiceInstance: "1472385723456792345", appEngineAvailabilityZone: "us-central1-c", appEngineRegion: "us-central1", appEngineServiceName: "my-service", appEngineServiceVersion: "123456", }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), semconv.CloudPlatformGCPAppEngine, semconv.CloudRegion("us-central1"), semconv.CloudAvailabilityZone("us-central1-c"), semconv.FaaSName("my-service"), semconv.FaaSVersion("123456"), semconv.FaaSID("1472385723456792345"), ), }, { desc: "Unknown Platform", detector: &detector{detector: &fakeGCPDetector{ projectID: "my-project", cloudPlatform: gcp.UnknownPlatform, }}, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, semconv.CloudAccountID("my-project"), ), }, { desc: "error", detector: &detector{detector: &fakeGCPDetector{ err: fmt.Errorf("failed to get metadata"), }}, expectErr: true, expectedResource: resource.NewWithAttributes(semconv.SchemaURL, semconv.CloudProviderGCP, ), }, } { t.Run(tc.desc, func(t *testing.T) { res, err := tc.detector.Detect(context.TODO()) if tc.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) } assert.Equal(t, tc.expectedResource, res, "Resource object returned is incorrect") }) } } // fakeGCPDetector implements gcpDetector and uses fake values. type fakeGCPDetector struct { err error projectID string cloudPlatform gcp.Platform gkeAvailabilityZone string gkeRegion string gkeClusterName string gkeHostID string gkeHostName string faaSName string faaSVersion string faaSID string faaSCloudRegion string appEngineAvailabilityZone string appEngineRegion string appEngineServiceName string appEngineServiceVersion string appEngineServiceInstance string gceAvailabilityZone string gceRegion string gceHostType string gceHostID string gceHostName string } func (f *fakeGCPDetector) ProjectID() (string, error) { if f.err != nil { return "", f.err } return f.projectID, nil } func (f *fakeGCPDetector) CloudPlatform() gcp.Platform { return f.cloudPlatform } func (f *fakeGCPDetector) GKEAvailabilityZoneOrRegion() (string, gcp.LocationType, error) { if f.err != nil { return "", gcp.UndefinedLocation, f.err } if f.gkeAvailabilityZone != "" { return f.gkeAvailabilityZone, gcp.Zone, nil } return f.gkeRegion, gcp.Region, nil } func (f *fakeGCPDetector) GKEClusterName() (string, error) { if f.err != nil { return "", f.err } return f.gkeClusterName, nil } func (f *fakeGCPDetector) GKEHostID() (string, error) { if f.err != nil { return "", f.err } return f.gkeHostID, nil } func (f *fakeGCPDetector) GKEHostName() (string, error) { if f.err != nil { return "", f.err } return f.gkeHostName, nil } func (f *fakeGCPDetector) FaaSName() (string, error) { if f.err != nil { return "", f.err } return f.faaSName, nil } func (f *fakeGCPDetector) FaaSVersion() (string, error) { if f.err != nil { return "", f.err } return f.faaSVersion, nil } func (f *fakeGCPDetector) FaaSID() (string, error) { if f.err != nil { return "", f.err } return f.faaSID, nil } func (f *fakeGCPDetector) FaaSCloudRegion() (string, error) { if f.err != nil { return "", f.err } return f.faaSCloudRegion, nil } func (f *fakeGCPDetector) AppEngineFlexAvailabilityZoneAndRegion() (string, string, error) { if f.err != nil { return "", "", f.err } return f.appEngineAvailabilityZone, f.appEngineRegion, nil } func (f *fakeGCPDetector) AppEngineStandardAvailabilityZone() (string, error) { if f.err != nil { return "", f.err } return f.appEngineAvailabilityZone, nil } func (f *fakeGCPDetector) AppEngineStandardCloudRegion() (string, error) { if f.err != nil { return "", f.err } return f.appEngineRegion, nil } func (f *fakeGCPDetector) AppEngineServiceName() (string, error) { if f.err != nil { return "", f.err } return f.appEngineServiceName, nil } func (f *fakeGCPDetector) AppEngineServiceVersion() (string, error) { if f.err != nil { return "", f.err } return f.appEngineServiceVersion, nil } func (f *fakeGCPDetector) AppEngineServiceInstance() (string, error) { if f.err != nil { return "", f.err } return f.appEngineServiceInstance, nil } func (f *fakeGCPDetector) GCEAvailabilityZoneAndRegion() (string, string, error) { if f.err != nil { return "", "", f.err } return f.gceAvailabilityZone, f.gceRegion, nil } func (f *fakeGCPDetector) GCEHostType() (string, error) { if f.err != nil { return "", f.err } return f.gceHostType, nil } func (f *fakeGCPDetector) GCEHostID() (string, error) { if f.err != nil { return "", f.err } return f.gceHostID, nil } func (f *fakeGCPDetector) GCEHostName() (string, error) { if f.err != nil { return "", f.err } return f.gceHostName, nil } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/gce.go000066400000000000000000000062651443314701600254660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "fmt" "os" "strings" "cloud.google.com/go/compute/metadata" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // GCE collects resource information of GCE computing instances. // Deprecated: Use gcp.NewDetector() instead, which sets the same resource attributes on GCE. type GCE struct{} // compile time assertion that GCE implements the resource.Detector interface. var _ resource.Detector = (*GCE)(nil) // Detect detects associated resources when running on GCE hosts. func (gce *GCE) Detect(ctx context.Context) (*resource.Resource, error) { if !metadata.OnGCE() { return nil, nil } attributes := []attribute.KeyValue{ semconv.CloudProviderGCP, } var errInfo []string if projectID, err := metadata.ProjectID(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if projectID != "" { attributes = append(attributes, semconv.CloudAccountID(projectID)) } if zone, err := metadata.Zone(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if zone != "" { attributes = append(attributes, semconv.CloudAvailabilityZone(zone)) splitArr := strings.SplitN(zone, "-", 3) if len(splitArr) == 3 { attributes = append(attributes, semconv.CloudRegion(strings.Join(splitArr[0:2], "-"))) } } if instanceID, err := metadata.InstanceID(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if instanceID != "" { attributes = append(attributes, semconv.HostID(instanceID)) } if name, err := metadata.InstanceName(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if name != "" { attributes = append(attributes, semconv.HostName(name)) } if hostname, err := os.Hostname(); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if hostname != "" { attributes = append(attributes, semconv.HostName(hostname)) } if hostType, err := metadata.Get("instance/machine-type"); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if hostType != "" { attributes = append(attributes, semconv.HostType(hostType)) } var aggregatedErr error if len(errInfo) > 0 { aggregatedErr = fmt.Errorf("detecting GCE resources: %s", errInfo) } return resource.NewWithAttributes(semconv.SchemaURL, attributes...), aggregatedErr } // hasProblem checks if the err is not nil or for missing resources. func hasProblem(err error) bool { if err == nil { return false } if _, undefined := err.(metadata.NotDefinedError); undefined { return false } return true } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/gke.go000066400000000000000000000047161443314701600254750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import ( "context" "fmt" "os" "cloud.google.com/go/compute/metadata" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // GKE collects resource information of GKE computing instances. // Deprecated: Use gcp.NewDetector() instead, which does NOT detect container, pod, and namespace attributes. // Set those using name using the OTEL_RESOURCE_ATTRIBUTES env var instead. type GKE struct{} // compile time assertion that GKE implements the resource.Detector interface. var _ resource.Detector = (*GKE)(nil) // Detect detects associated resources when running in GKE environment. func (gke *GKE) Detect(ctx context.Context) (*resource.Resource, error) { gcpDetecor := GCE{} gceLablRes, err := gcpDetecor.Detect(ctx) if os.Getenv("KUBERNETES_SERVICE_HOST") == "" { return gceLablRes, err } var errInfo []string if err != nil { errInfo = append(errInfo, err.Error()) } attributes := []attribute.KeyValue{ semconv.K8SNamespaceName(os.Getenv("NAMESPACE")), semconv.K8SPodName(os.Getenv("HOSTNAME")), } if containerName := os.Getenv("CONTAINER_NAME"); containerName != "" { attributes = append(attributes, semconv.ContainerName(containerName)) } if clusterName, err := metadata.InstanceAttributeValue("cluster-name"); hasProblem(err) { errInfo = append(errInfo, err.Error()) } else if clusterName != "" { attributes = append(attributes, semconv.K8SClusterName(clusterName)) } k8sattributeRes := resource.NewWithAttributes(semconv.SchemaURL, attributes...) res, err := resource.Merge(gceLablRes, k8sattributeRes) if err != nil { errInfo = append(errInfo, err.Error()) } var aggregatedErr error if len(errInfo) > 0 { aggregatedErr = fmt.Errorf("detecting GKE resources: %s", errInfo) } return res, aggregatedErr } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/go.mod000066400000000000000000000013751443314701600255040ustar00rootroot00000000000000module go.opentelemetry.io/contrib/detectors/gcp go 1.19 require ( cloud.google.com/go/compute/metadata v0.2.3 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.13.1 github.com/google/go-cmp v0.5.9 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( cloud.google.com/go/compute v1.14.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/go.sum000066400000000000000000000056141443314701600255310ustar00rootroot00000000000000cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0= cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.13.1 h1:hR+NqMEDDSR8hLc5ZybuWtPfhmFVZwd6Ft7n25XnVjk= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.13.1/go.mod h1:Xx0VKh7GJ4si3rmElbh19Mejxz68ibWg/J30ZOMrqzU= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/types.go000066400000000000000000000030611443314701600260630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" import "github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp" // gcpDetector can detect attributes of GCP environments. type gcpDetector interface { ProjectID() (string, error) CloudPlatform() gcp.Platform GKEAvailabilityZoneOrRegion() (string, gcp.LocationType, error) GKEClusterName() (string, error) GKEHostID() (string, error) FaaSName() (string, error) FaaSVersion() (string, error) FaaSID() (string, error) FaaSCloudRegion() (string, error) AppEngineFlexAvailabilityZoneAndRegion() (string, string, error) AppEngineStandardAvailabilityZone() (string, error) AppEngineStandardCloudRegion() (string, error) AppEngineServiceName() (string, error) AppEngineServiceVersion() (string, error) AppEngineServiceInstance() (string, error) GCEAvailabilityZoneAndRegion() (string, string, error) GCEHostType() (string, error) GCEHostID() (string, error) GCEHostName() (string, error) } open-telemetry-opentelemetry-go-contrib-2135499/detectors/gcp/version.go000066400000000000000000000017731443314701600264140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp // import "go.opentelemetry.io/contrib/detectors/gcp" // Version is the current release version of the GCP resource detector. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/doc.go000066400000000000000000000015131443314701600227170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package contrib is a collection of extensions for the opentelemetry-go // project. It provides 3rd parth resource detectors, propagators, samplers, // and instrumentation as submodules. package contrib // import "go.opentelemetry.io/contrib" open-telemetry-opentelemetry-go-contrib-2135499/go.mod000066400000000000000000000000541443314701600227300ustar00rootroot00000000000000module go.opentelemetry.io/contrib go 1.19 open-telemetry-opentelemetry-go-contrib-2135499/go.sum000066400000000000000000000000001443314701600227440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/000077500000000000000000000000001443314701600234545ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/README.md000066400000000000000000000023151443314701600247340ustar00rootroot00000000000000# OpenTelemetry Go Source Automatic Instrumentation This package provides a code generation utility that instruments existing source code with [OpenTelemetry]. If you are looking for more details about internal working, see [How it works](./docs/how-it-works.md). ## Project Status :construction: This package is currently work in progress. ## How to use it In order to instrument your project you have to add following call in your entry point function, usually main (you can look at testdata directory for reference) and invoke instrgen tool. ``` func main() { rtlib.AutotelEntryPoint() ``` Instrgen requires three parameters: command, path to project and package(s) pattern we would like to instrument. ``` ./instrgen --inject [path to your go project] [package(s) pattern] ``` Below concrete example with one of test instrumentation that is part of the project. ``` ./instrgen --inject ./testdata/basic ./... ``` ```./...``` works like wildcard in this case and it will instrument all packages in this path, but it can be invoked with specific package as well. ### Compatibility The `instrgen` utility is based on the Go standard library and is platform agnostic. [OpenTelemetry]: https://opentelemetry.io/ open-telemetry-opentelemetry-go-contrib-2135499/instrgen/doc.go000066400000000000000000000014141443314701600245500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package instrgen provides a code generation utility that instruments existing source code with OpenTelemetry. */ package instrgen // import "go.opentelemetry.io/contrib/instrgen" open-telemetry-opentelemetry-go-contrib-2135499/instrgen/docs/000077500000000000000000000000001443314701600244045ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/docs/flow.png000066400000000000000000002376551443314701600261030ustar00rootroot00000000000000PNG  IHDRj iCCPICC ProfileHPSǿ{-! %@A:IPB;kADl誀Rdba,uAe],Pyo{̙o\( \8V E! `DFE3p8@6奋YAAw{x|RR> X[!iA{&9~G&9v`&40 <˕@f yF&/!#l) EvMII#|acɑ'M3Vx,SYߖ,qr7J3IJ(va SS a^:;z\O3't283,H aIjl8 5\Ҥ0Y>Ag'Fp0| 'ְey4Xֿ@1)ߝWȑH;ۿ@ĚLxzքAzA,"[kd04À RA2/O2+3&NgI  r g1amim}~ҧ!D9ۨKĹٜ@|83@&w]"4 0g ,<RW``;J~p')΁:}` D* @f5Ą\!/( (ARh5* R T .C7N Co0 &4X6LáR8N\x+\Wz2| /1@PtDQhTJZG*P5&T+.5ƢhEy4Zt)݂Ca(  Db1+0ybL*>fұFX/6 ]݂݋^vbc8Ngs⸸ \n8"nOkh/W/H Mۄ8QhDt!%Uc[Kr$-" II%>'ٔ&/!K[Gɗo)!ŝMɠlTRPR>Q,8r|urerrw^ YOߖQ (* k*t+)RS(V)PR)*y)r)]QꧢzT6GH=LJaiF4-V@;Ak*+)*+T.S>KG z2}ysjܙAE]]ERr_*CK5Iuj5"jԮԝyj4iiijih5h^Ѣkk%ji]֦jj /j`(3XdF 1#9Ӯ3kԋ+k_ZZi`۠a&!##QQccqq= $dI)ljg`Zfz 675뜋8W4bn9ٜei^mgAȱhx5O^Z}L;Mvv_%51L3y''{ SN9;'9W97/x~ K+5k׭홻; ˄:za!vba_Dyx{{)yyz=Ys÷q*9~~kZ!L$M ~ v.x`haC  |d"좠Ee[n , y-Qq49\>|Ixeψˆyk"oEE qG{-޵x`ݒ%]K\zcڲe/.? Vpb9屣<6o7%ߝ_ q.qqC.;FlauoIIG&#kS)1)gEJ$QKVN8Oܛ收+mT/9/Mo̠!QX/5,W*l2ڜ5**ު:7[Zsp-6vm:u?!io9996Fll]yryMΛQcf{6,,(.OV?45nk6mcwpqP0炝EwQl[7qtwoI@I=|)M(_QV[Q^;_ၞ>+ +aez~8p̟+)8hc-UU۪ji%;Nxh19XK-8 NJO%旮SO3Oל18S^G˯Gz;mnrnףtΕW>B./\߼ѕ+Z_z+֋]tM͆[~ݾǎݹ|{{/ӽ3 뇙yDIS^k{ϳYȳGe 9y`йa_ SWƯWhk7[ު=]X)?TxSσ+ྔ|5㉔ 1WPqq9 % *2COSMLO<=sO=5Hؗ8zD#Q;mld>3N铆EXxN҃<M&Um?Oɞ\eXIfMM*(i>ۙiTXtXML:com.adobe.xmp 1 2 1 2 1942 787 7@IDATx UU(( *i8I)6={/gef9&fi6X#RKDMC qBQ.6r=}dzZk+sGp @ @ @ @5\Cb @ @ @ ,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @g @ @ @ ,QI @ @ @˞ @ @ @(+ \G% @ @ @,{ @ @ @ @rY @ @ @  @ @ @ @eyT @ @ @ @@k м/]濷4,X4_,,[^Ӽ'lv4@MZN7 ;M7iӪA @ @MC@`i'$@: @ogrsw @6.ҧk}?iѢz @ @,be33}ySMVa ni={s: @ @, \w />/ϗ37!vmNCc۶YEJK-^>, Ϟf6'>qݶ CҾv4 @ @D@`H @jjV;ulvqg-–uL% o/67WC͊iV/5_ @ @ @y,7hT wN Κ|Þ {ҳ$L-W1?+I9?U8B-E  @ @hM>'oOK'ߣva}r[\> 3&@bޝ(<Čko'cڶ[0]CV  @ @ ,Ιhtǟy3Tz݃m @xi&hM @ @ h,ߘnmv Gdrc,p}{_ly~tuDC @ @*N@`n @X`eIpfʕIv ٢Tn;ms2YsƯ ! @ @ POz9)2Y\ݺ4]uз{k^ySg: @ @*G@`r @O͜=wyKSHJoÎ%Ú7U @ @uX^G( >ݻuXp]K}w mڴJνgI @ @lT(/0q0g^Vm)[ ,MڶN~v`Q  @ @kX^zl$5+B~r[>mFX?A v$^ZΜM @ @FX(.J <=pIAZv1-T-Z\漻j'Jq @ @ P, \l!0m8:o.lUA @;얞H @ @ P jxUZ&М:ozt[K2Κ  @ @@,W˝6OV-ZO4>۬y9aaJ@ @ @jV(MI%mٲEA )X  PJϳ7^X2 @ @*T@`Boa P .M:k[fO@;  @ @lʾ?FG@ _jA*0m@e-Z$3/4  @ @f- ܬo T+:ZToq /f  @ @ PavC Q`| @~W\e @ @rsG @ @ @X^O@ @ @ @ @ ,7;l~ @ @ @XOy  @`#̟nxWNF"0gCim69oNnѲeraa}w:KӼ @ @Xڄ @&{gڨÜʌj2y6d`f0^O)k_IᙧL|#>$e'lҫ"@ @ @f.`+f~M#ȃyLQPLB׿$ *'+w߇{> @ @U@`yD @2\kie܉K/.{oHsI>ig,Y% @ @ @@9r: PA/N.3= ?ܔ),]4 lŖlLg9iCs_8;ͿkM @ @ @w,QG ֬h>sO~ ,_Z_!555UV5 vumw?^cXW2&Vۇ92SW\zK+.9?xi}v2 @ @ @P~Q^  @`,]8\yOʕ+ޭФ%KB-™ЦMpޙv:#;4fʾ ͜1=ʋN7 awk~yYϿ ӻ#Y߁I&o{CxhҽaO?#O=35?¬7_O}/ΛmEa?̜vc0CXn{&mh𷿄G%a>.]6O+LqpB >Ӊ] }vüv O /KO|WX"l_9o_Y=&=nan q;F|dP2E}܉, ou0Iypm9Y @ @ʂ2Y]XxuW?{ZGijo]6 ]&}/|dW‡ZDWt}a&ɏ>N>v5cPkqQΟ[,9ùWӲRko mnRdafL>wWI7-p>sZ1Pv\*/Ly̯~wKvԱf^4W#]vO/uW̜S;7v_*g3s{>>5IiÎ _Ҽ -p󝏇snN3&om}MK^_'Qg sTJ~n]xN]q{ʺ>珸:9+<9Mw?Tb'˓{D8|wx`]ԵAE K4Ova߱ϞJ,c6Y1W>?uAEM;uND3똉㫽B=;%Virݶ 37sv @ @ @rU#@Q`*ةn;n-*RQٛnGXpAڶSA6XDϥ 3Ӷ={g1lҴ,'_>µ\^}efxuvC{5˾v.*[QSP{XenEkl]9A @ @ ,QG@Io߾,_K/wۤ|b+޴{{k]lE-Zd1SXyrs*좓oEoߡ,7Ф٫oT*߅+k&@ @ @Q@`s@*XbEg\2YYi[nz,]$gGlkka9+W&ٖ-Zfc]}б @ @ @@Fk@M eǻ!&}2.|oAXxQ)d~1c ?;+vlԩtU{v;s߮ zo @ @ @B|p t%/uċ?On}v({wyLFdZ6dži~c$jo}τ3C8~'E.Զߙ6p&cWz9iTbnA`r)&e @ @ PKZh[l-3'<v#/\nRʫqQz/N.L$ SjmF,Z^&X/ =2GURᄈsmzX) @ @@e@)=蕙3™90wq7o^{c1n:t4~1aᲟ0'=|r}-koI19ủm៏=.!n];k_t\ >S_=- 2n^̮dߡN  @ @ @@F@`9!C-0؛ ӘGܞs səˎ?_VqwϿ mYirQa9_!?p~^ 555UViY>1sv#M @ @J $B4M#:.mcׁ{n8|fq't:mF_y%/W;x\ ۏ={V6Taܢ;G>fJǐmAu"i#q.* @ @4r8\M۶kG˖-\Fvf&Иo7 7x^hղxkZiհڵW%߱ϟ^pȔf΍_1oߡN'i&Gyf*je+cс.ŵE^.nn\Z_\oҋ!o[}KHcj˖- q &~Cۆ}(۱h]m-l[= t۪{]٠ԓ>^croŋ{f<Ŗ2dlH|<̞ ۶lK @ @(l/+h\6gcmnvy䳱Roکs8Ç$-H Pq/Aګ+﮾<ęL^ @ @I@`yM2  @@8ȣAC̜t5s,9 ={I @ @M@`ymB  @@۟wᕙwi_qfpJgoQ_O @ @ @`mޱ6! @ l׳w Wd/l:uvcѿ lҮ P  @ @ @`c ,o; @!~j|vV @ @IVuҘ @ @ @' \}܌  @ @ @ P':qiL @ @ @X{n @ @ @r4&@ @ @ @@ ,W=7c @ @ @I@`N\ @ @ @ @1 @ @ @$ \'.  @ @ @ P}w͘ @ @ @uX @ @ @>fL @ @ @: ,׉Kc @ @ @Trs3&@ @ @ @@ĥ1 @ @ @O@` @ @ @ @NuҘ @ @ @' \}܌  @ @ @ P':qiL @ @ @X{n @ @ @r4&@ @ @ @@ ,W=7c @ @ @I@`N\ @ @ @ @1 @ @ @$ \'.  @ @ @ P}w͘ @ @ @uX @ @ @>fL @ @ @: ,׉Kc @ @ @Trs3&@ @ @ @@ĥ1 @ @ @O@` @ @ @ @NuҘ @ @ @' \}܌  @ @ @ P':qiL @ @ @X{n @ @ @r4&@ @ @ @@ ,W=7c @ @ @I@`N\ @ @ @ @ZWߔ͘C`ѢaEMMRkڴi)k.̯TڷZn%,_/^V:VZ]C4³!+lmϰiFWfHưen97Hl3 >:>'@ @ @bW4[T%~ [I#?.LYsȼ3.{*_pOM o _:unv%|sgNԧѰ!3]xo?qjlcd^yc׾~?fZvO% @ @ !7  P{WQP9R|Ю] .G}>N ?tGXrzubŊ:ɍ9R/U|i!~}l8ȣå6tܴSnD˖.I. { 7N;_bZ/3|// s~+W 7{N$A @ @@U ,Wm7ilX[|/Î:v U~bʣ~>4sg?VOX}Gc޻s3ڙ[xOZtY_Ig|+U&uS{(rõO$  @ @4@Ow P5* :&ZW'SZ-nz>a̵WHmcׁ{v[6%/ 9zF?铟K1qONΜ$C @ @zX\4 @5Wjb9tټl]9w$mu3TSzNU+|C_뗿)=t΋/ =|գ3vcɏ>mĢ煭Z\vwvU{>˕5؛ oZzɑv:?7q[]}yRž%ﴍ @ @6@>  @"2f[lWp5i]˖\UH{ܗyn/^xpg23';ۇ}pp8]0e#<68kà 7;kdW^uY.3~{lvGd28}Kw#>aħguѢpwpM =p׊#eO}u u @ @( P @^P.ٸr, ^byMf׾Z v ٿ#v}pم?}zx73?t)ܹ+[•16]Czp~v~piYLUË7_GSOhknv/ %7^dLbs.8^cͷLǮ(~2,ȭLW +d_R9^zaG|,_~ߜ[[Q~U\`?vuc_93Sɏ<|bn/mIX0o^4/u1{Y_~AG\俧$ @ @hHِW4k•qÎ:.S2+kol [ɠrP#PxvSU,A‹իzIEulpx浏%@u t>N8^IW>Zjf-[k * shNwj+]T.$(?-,^=wޖiWn܅G6m‘ˮd{|s  @ @ +|Hn4q56~;Ly̌mW!ǏdraEuǓ]]o|"c.<~v^9m9ok O]c.մnjο-usBb'#*cN,,Z|\!]8}ƕ3?󉃆 >GGނǕq;R \{C cyUԷL};0{l_o͞[4 @ @B hCJo;p>j cgjp̾'"~`={Ws]Ҳɏ>k1Xݔw/~}M7CjZtMnu9nK'L5./wݸU;]u]:rQEk}w vݽVZϞ=+-z٧ÝWr~z/v\)]xY.UV>2m  @ @ PNVt @: LP>~hPxqsi[o9 -Z5'^W7S$AK3%RqgR١_I.:i vݷ5thіwW3l}0u#n]γvr _ރWS+1\٫]/v_Z+>/.:L.ڸT8+  @ @h, XWwhh7!~q, LkW+BKQ / ºZwʕ/v4TYk:ڶ$'ß*mrIY̵OTǜpr.:p޺U=K^`^6kgڕha+̓sF]R\Ѯ]5vѮ]8JT @ @ @uӜK. ![X\|7s\Z[m3_z?gz omVncǟ ,?ܽӎ8L~MOj5]C/xvu&=+ Gū 4v{m.9mE (l#O @ @ xr}Gqn}}X;tLAXq]2ocɒч'ewk&_-A{Uf_3ο9Ӱ2;)S|T,y{;zͷ̔UBf[{g6w..j @ @X' @`c/raC,YZ4~ib~⟏1q f2e˖fjwsL>n߯9_y~Y{K~/Z0c>/*GCο>#NLԿ_8đ:pϢ.~C'<L~o%gT ~޼q~[tzj @ @hp[a78  P=1uc3޾7ݑ){m>{bp۟o IY{u o|֬7Bmz<191/CBθr85ǙO~/Î<:=w^tbO}.{!~c s֥z)};~̉+.\y56Xϊ QG<>yLg+lŖɻ/74-*L=١_}]Cn[K̜WfDa]|&;uRL @ @ &`rQ'#>UXx!|B\^}v18]x W٢ oa|f/#>{.(zQҬ},JקS*o:t4m_u}ǽ=Jޣ_ *oz~\$cRA帒z؛>=^.{Rf(=t&_;ٺc?~Jji @ @4r#01E=b@YQe dKhL_~՟iAD\Z*-^PIRw 'b ?kwc7Xw'؏om}ݲ$~aGwI>GZyDzv&wWXbEϽۼqZn+M @ @,G9 ;^~ྌD~;ϔyT6=ִi|ﯿ= Dzqw>N9}Li&0ckwyػBNxMG9(j}D\ ujYW]q>ڵk_;6̭ 3dG=dy,,ThƓKT{{}˯[%[ԪUfkC(U_ʱp< ~٧N9czflv  @ @ А-V掆P_ ]Xxuk#6-|/<Կ/m7BrS;gv.7;lYhۮ][ܮ98Iz1st-]buu{n| /MoDE6< ľΜCߝC޽w(EWᵖ-[{ ڴm?GKVo}/|d/ |'n0{nۆP5> @ @>X( @+RFυ-SWtxС2 Ġ{NO|܊IY}v'N~>ls9XcX @ @"PZNPMTŋn%\_3Ong%v@IDATpT'Lz=pv㜷 4=3A呹-RP9 @ @MN@`2&@G^ s3?D 9@f+熎vJR&\v&A @ @Xn e @X #x)i3lܩm+~^4oa H`9Of PS",]{^g hZʋ,K=u+ٴ @ @X-_V[H @b;?pd|Ӧxr+#@`@aͷ'c)ڷ @ @ryN@u [S-I?a l hnKvᠽz5$ @ @kh2wZ TKu}2ɰz<_С}J Pqr:[9{NUa @ @rfC@8ajl;ulڥgumdI@ ԬS~9L~rf:#! 4/A @ @@Xn b{?<=rsc2 lh?jT[`ǣEsʑHC @ @@Xn,RgfRڪ#f;>lz>u߼JeL %<:憙o />7,Z,;nٷOvNi @ @C@`yG @ #I֡曆چچmZg @EKrw|ʕ+3e8d>oO̒!@ @ Ќ4Yaڋo_z;Z--l-l5~ q } @ @ PAt3  )s33w, . r 羗_Ӑ\&C玛rMۆnuwznݹ @ @- \[C @ @ @Z( @ @ @ @kaH @ @ @ @@r @`=͛g; @ @*Q@`1 @&*pׇm&{7h0l @ @(h2w @#~G}4=uԨQ!~훖I @ @ @@b3#&@+pWOF8O @ @ дXnZh  @@6mZW_ȑ#̃Δ @ @ @@e ,W1: ФfΜdIrq%Ce @ @ P˕{o4ٳg 6lX`>|xZ&A @ @' \yĈ @@Xpa`5kV:!C$#Fe @ @ P9˕s/Tʕ+3y4( 0vii @ @l|T5\yԩCYgI @ @ @XxL3fL`=CiGi @ @lX w @`=&Mǎ)n?}͔ @ @ @@ ,7  @ 0eʔ$|uez?ӓ32 @ @ p g' @MF)!@ @ @X^C= @A`̙aI&qI @ @ @ ,  @,0{4`t4Æ KÇO$ @ @ @~ss Pa .L̳fJG7dȐ$lذ$<|L @ @[@`yc'@Z`…iy֬YŐ!C#2  @ @l,% @Z+WL3fHk O;L @ @- GX5\;N߿`>묳2  @ @4rcI @cƌI̓'ONիW`5jThӦMZ.A @ @ ) !uMhq%'u5 0w%- @ @ @X$@l &$ǧw! 0#- @ @ @@C ,7 @ 0iҤ$윾  @ @6O@yL pX`zz:===aaa!ݻ7{n) @ @渻* @CfggS<77ݽ{w ;S @ @ v5 @GOL{׮]1` SOA @ @7U @V(橩tΝ;c|饗 @ @, @@___<11vǀ+H= @ @# X^Wg%@X0:t(}۶m1`޷o_(++K} @ @k' X^;Kg"@ 08p ]ONsEEE+ @ @8q: @& ĀnH#زeK R_A @ @˫s$ @@ŀQx짦&o @ @ Weo @<9ccǎ  @ @O@||N"@( 0/gӷA @ @- @@ LOOǀ',,,ݻ7{n) @ @8`6!@(0ͥY޽;w^) @ @x`&: @E*0??晙4]vŀ /L= @ @?,BE P")`J޹sg /S @ @ `_ @@I OW\z  @ @, X.7w @$000C޶mbo߾PVV  @ @& X.7_ @c ŀiO>9 @ @ P*RYi$@XH otܖ-[R\UU  @ @. X.6? @_sOMMMN @ @b,㪚 @ s_~1`ޱcGN @ @b,j  @ LNNƀ7Z_|q >윾  @ @ X.U4 @ sOOOXXXH߻wo MMM @ @ PB_A'@T0ͥ޽;--- @ @ PB]9&@+0̤ڵ+̭ @ @ PhB[1%@k0OMMܹ3 @ @ P(BY)$@(8ybb"Osggg) @ @什`9W @ ^``` ̇Jsٶm[طo_)++K} @ @|, @@Q ŀi~'|r +**R_A @ @ B P###1`|lْ檪W @ @r>1 @X /="&o @ @f 7Ku  @xؿ1];v @ @ w= @Gsooo_|q >윾  @ @% X(i!@ p1` 騽{Ԕz  @ @! Xe @ 0ͥ3޽;--- @ @ un @k 0??晙t]vŀ5 @ @C@I @`S<55s0 @ @Z Rӹ @l@___<11xǀ3 @ @B@A @`b|С4m۶ŀ; @ @j˫s @<ҨN>0WTT @ @J+? @< 7ܐFe˖0WUU @ @ W~ @ H`ll,߿? 挺+dȮ @ @ p,t|G @cߟ3/<۷/ر#o @ @rT @d {{{sfvǀ @ @ p`H 5 @"sOOOXXXHݻwo|sSSS) @ @, $&@ PB)`K3߽{w [ZZRO6w_[·=-l߾=z֭Qz\Y @ @ X^T$@ P()`I޵kW [[[SO:n) ozQOp9焿gqQ9/B<9oO_pE3<3\{F};җrv+\/x #|4zN6 @ @ܱπ @ybb"O?xsggg).ӟ4'NO}SCv.櫯:8=˧vZ;)_n!nu]SNI) @ @G P @ b|С۶m[ CYYY+rI??}8Sop%Y=oi-X>aB' @ @%/Q%' @zիG>𒗼$o|#Mo [n W]uU~%LNj/}^׆}cˆ>O~?x߿TM @ w,2 @w0/=:9-[UUU? ɟJY|饗Ưoخw_=dq_;{v>cկ~5:{g~W5<)OYrz @ @@ pQM @z tuu5559R柅rBcYG? z׻.~ϿۿywK~+S`9[-eKwFg!]Z~ @ @E, X.55 @)0>>>#;vX;*{nn.⬳Ί"WzYꫯ4Xw~/}w>? Ow//ߟgBcc-5 @ P?E89S"@ @`<_rx^.1_|q?PLOOL3{LZ|~~/ݩݕ㲿=2ٚ,..{R|011L0g!@ @ L@\` f @M}nkw7<1q]w]hhh{ 7tS {]swO~rj7>OC{zz“]YY:;;]Yo}+} _B:'~._e~gotr @ ]#@ PX|3cx=/K_Ұ{//5{MG<9I㭯~~a{YI?q={>b˖-Y}d蝳  @ @cd @||svLX>}+DhiiyS3ﵜc.+|s ׿N=tɕcOOO;pe__ ;w {w  @ @4˥fI @`iyjj*# (B{{{z}.=:}'ɴ] GWcDqڿk>.{ . d^ s˽Κ @ @@QxvQ,I @_n{g/~1}oN`#;Sr(>O~PSS~>|_M^{!ϗ _wNc>22w);Px_nݚs \ҡ @ @@ |  @@1 5 v[>:8 C}?fzm۶-'?|?gQ7|s Np~ӟ755-}('??۞vһSfcޟ}w !@ @ I@\He @DUzU8x`G>^Ye ~ӛꪫ~;ٟYx\ۿ۴_.>qCPg[y6;(Ggqy{^+B6{7| U\! @ @@ ta  @@)d ';}9 o}[c79s=Eٙƛo{BK.!cyse?K/9m?Ҏ_GYYYHqV @ @) X.u5+ @%𲗽,>ӟtx+_87{}B;v_|qpEGwd=.;Cy݉\*;;k_ڴOVȣ'{0_d!@ @[@\kv @ J/~qȂ/| K.Ic_?#x{4lN}sCGGGx{xWv~#N_779 ^ӄ7]Y=;۷1>:tru#˿s\Ȃx ;{T;txCCC @ @@q <#ҎL✷Y @ Pa7g#97^Wo1gGpi=N;{qv}N9x^vٹsgKw0g>nu]!;OɮU]]Gk&u{|O @; |  @@1 dwfw}c{uׅEa޽ᦛnK,088ԧu]8P9;(>;Yg9.wAG~^;~-Ļ:Som5 @ PX.҅5- @(0;;` ٝKxsKKR+~/,,շ~{ygD~3 <;?$/ KǥC-| ~zضm[n5E6SSS'{3̐9՜1 @ @@  p  @@ ϧyff&qd};ӗ  @ @U WM@ @6[`qq1]K0/&@ @8 9 @ #'&&Ҡjkkcٙz  @ @ Wn @X``` ̇Jswww(++K} @ @ ^ @P 8F^YY把W @ @[@|l @ P###=i&)`J} @ @]t  @(20̬+dȮ @ @`g* @J@`||<9;r6 @ @B,+ @ @$&''cۛ3솆  @ @@) Ky͝ @0==枞D榦S @ @JU@\+o @Φynn.}斖S @ @JM@\j+n @S`~~>333i0 @ P*RYi$@ @`E)`Jǀ= @ @b,  @',w0OLLsƀ3 @ @b,ʚ @k.000CsWWWǀ; @ PLbZMs!@ @`Cb|t0WTT @ P bXEs @ @`SFFF{S\UU  @ @@!  y @`xB욚  @ @@  mŌ @s;::bcǎ  @ @@ e @soooΘcr6 @ @. X2> @ V`zz:===aaa!cϞ=1`njjJ= @ @ :F @@QΦynn.ͩ9--- @ @䣀`9WŘ @(J0̤9666ƀ5 @ @|,j  @%!橩40 @ |Xc @ @dB扉dP[[S @ @6S@M @CIuuu CYYY+ @ @- Xhq#@ @1b|Weee +**R_A @(FI @V 022<<<*//OsUUU+ @ @- X^oa'@ @ ŀypp0,]]]!{DvMMMN @ @`= @Xc0眹#;v @ @`y-5 @,099ޜ+d744m @ @B@A @ sOOOXXXHW߳gO ROA @8Q : @(0;;湹40 @ ZjG @<OLYccc [[[SOA @X`yb'@ @@ ,..yjj*> @ @`xG @ ;'&&kkkcٙz  @ @# I @(p0:t(ͤ:ݡ, @ @˩ @ @cGGG*++S\QQ  @ @#5 @(0ٖ* @ @L@ @%*066="&o @(]r鮽 @ @ ǀ?G#\WWӷA @`܌  @ d {{{sokksCCCN @ P:Yk3%@ @q LOOǀ',,,c榦S @ @! X.u6K @X`vv6sss0 @(nrq @ @S<33S @ @) X.u5+ @b c6@IDATޞz  @ @ŵfC @  ;'&&jkkcٙz  @ @8űfA @MCcR_A @`p  @ 7CCC1٣iL)`H} @ Px[3#&@ @@ Āyxx8<UUU @ @ G@\8ke @(0挹+dȮ @ @[@ct @(h0̣#\WWӷA @䧀`9?Ũ @ PT1`͙W[[[ r6 @ @,z  @Z`zz:===aaa!uϞ=1`njjJ= @ ?Y #!@ @@Φynn.ͻ9--- @ @6_@k` @(Y0$0 @<ٻ2 @b K}}} SOA @l`y] @!w0OLLjkkcٙz  @ @`gJ @ 0:t(U]]PVV  @ @`} @ pCCC1٣L)`H} @ >quV @Xc03* @ @  @ @`b<88s="&o @8q: @lx sb @ @V/ X^#  @ @ &''cۛ30744m @ @+, @ 1` i{sSSS) @ @ Weo @s0ͥ677ǀ% @ @ ^ @ P`)`Iollskkk) @ @c [ @(p0OMMǀ= @ @]t  @ @B扉40wvv @,z"@ @ClcR_A @ XW@ @%+044=:: *++S\QQ  @ PR^}s'@ @(022$R^^檪W @ @R,⪛3 @,+066ﻺB욚  @ P*RYi$@ @s1.溺  @ Pb_a#@ @U LNNƀ7mmm1`nhh @ @* X.֕5/ @X30􄅅t={Ā) @ @ŸD @"0;;湹t0 @`V\ @ @`CS<33S @ @b,* @lb cޞz  @ PB^=c'@ @ ;'&&Ҙjkkcٙz  @ PB\5c&@ @w1^) @ @soooΈbАӷA @I@HB'@ @*0==枞fgϞ0755 @K@|, @ @"M\Qsss [ZZROA @,/G @P`~~>333i1`nmmM= @8R@| @b Ҍcޞz  @  @ @ ;'&&Bmmm ;;;SOA @- X.7{ @ ]L"1`eee @ @,ޚ1 @8P GGG>)`H} @`tL  @ @q Āyxx8S^^檪W @ @@ ͐ @Z`ll,̃9!s6 @ @8ŹfE @T`||<9s]]]N @`l @ @ LNNƀ7:mmm1`nhh @ @,: @P0􄅅t={Ā) @ P_C3 @ @&0;;湹40 @ W@\kg @ @ oS<33S @ @@  o͌ @b 8cޞz  @(rᬕ @ @!mݖ][[S @ @@  @@ ~+{ @ @"066wuuŐy9} @ pl}|K @x sf溺  @X^@. @ PD1`͙U[[[ r6 @ @ W@a @(b0􄅅4={Ā) @ 3,T @ @@Φynn.ͺ9--- @ @  @ @OLrhllskkk) @ PR^}s'@ @b J}}} SOA @R,⪛3 @ pT2vmi0wvv @$ X.6W @ @b|tLuuu CYYY+ @ Pb_a#@ @NH`hh(̣<)`H} @U@\+k^ @ @ Āyxx8< [nM} @M@\l+j> @ @ ŀypp0:]]]1d޾}{N @A@\ h @ @ ǀ?1` @ @@!  y @t0挥- 9} @(Dr!1 @ @y'0==枞ƷgϞ0755 @& X.3^ @ @ fggS<77斖S @ @P˅RI @| gffcښz  @什`9W @ @X\\LTK}}} SOA @|, @ Pt}}}1djkkcٙz  @䛀`9Vx @ @\cR_A @|,* @ PCCC1`M󯬬LsEEE+ @ wm @ @a0'0۷/lݺ5 @ f& @ @`0|C۷m @ @`%: @ @s1` @ @z [  @ @sooobАӷA @, @ @H`zz:===aaa!uϞ=1`njjJ= @C@I @X0ͥ+477ǀ% @XKZj: @ @`S<33S @ @`-k @ @MX\\LTA}}} SOA @,c  @ @y"w0OLLƀ3 @X`y5j!@ @@i1`eee @ @ W~ @ @hueee +**R_A @G,?  @ @,02240۷/lݺ5 @8`h2 @ @"`άbȼ}  @) X>RCM @(r0̴#uuu9} @ @ @%(099ޜٷŀ!o @,= @ P1` IcϞ=1`njjJ= @+ X.ݵ7s @ @@M\777ǀ% @`܌  @ @GOLگ1̭ @ @t˥fJ @8n0OMMcޞz  @_@\kl @ @ ;'&&yjkkcٙz  @W@\kkf @ @5CycR_A @@q k=͆ @ CCC1٣Z1`޷o_8餓R_A @@qc͂ @ ###1`N.//O֭[S_A @@a  { @ ccc1`KWWW oߞӷA @@  o͌ @ 1`_GGG r6 @(rᬕ @ @ B`rr2̽9mkksCCCN-6/?kq* @ @`G/"@ @ j>k wygxs]wuE/zQػwo馛V}+C. @ >X^Wg%@ @xsOOOK.斖[mq9p7N:iq @GpQ`  @ @F)OyJxw#Ų;/> @ pMt @ @AO|bx[wSOWg?.袰spמЕ?я> @Ga @ @@/dȞHGGdwvv#٣8vԧ> @k#qt @ @U5 v[>:xo=۶m z׻߿3_p!{4 @k# X^Gg!@ @8WU#HxK^t]w7M*\uUq_!7 } @X8:  @ @dah'?^3{o}kغukxҗpe׾v"@ @c @ @`^O|ӟtx+_Gp}wxF|׾Gٵ^ @NL@|b~&@ @XGp.t:<_~y[S oxC^!@ @`Z @L@g b8 @ @!㹧@c't  @l7bE @ @ @' X.53b @ @<x#푾}M @`S˛ @ @-l;V+!I @ c9p @ @_,ā>-YKxhi\o @y/ X%2@ @ @|xݟ=zC p,t|G @ @`;|ȭ3<3+zM[+9$'\k|>?v՛G?4wԡ2 -+;>o?/it?.uAR?ἦ3JORxvVz  @5,S @ _>5'6|/#@X@ƠNGq/G㸾I> @\ {vvR~xz[vv׳Wz'(#:rF~uu"m]ox_ Wß=ljZoԴw] RG @@x ͇l?! @ @`3b߳@x ^ǿÇJ=~'rgo[6T^W~o6Ç6K  @Jܱ- @ @8,cp>K*/5c;; t'=V=!|gO9/HMvxCݟ0~sᖛn OzJźg7g-\16zcí_B7NގplO{zU!?z;o:w&KB_\}]KQnPF%DETB@DE.EBBK_II o߃3ۗyqϜ9So̾kW'6cU! ΒC˩%] k&V5kKD>x/r Z2f,Uz] 55Hr-E˗.■4sown*gNH DRR5yT9ǝ;{\zUs8~L8VvS*kBgш @\ =зoFŽmޘPe@@)`\$[|56Z[tXh-ժ+ɓ?]ښ^X: ?")WY^q 5aoeRt4 vNkdgٵO:bp?yWkV.Zyc7V$H  uM)SuլtkwϐIFlY_b|?n} 3AcUѠrq6uu~;=11#c-/u!=:YKϚo?~|אML[dɭn|" Wf@ nݺz WߘOmI`9q   }eͱl=Ed@p ">x9=/3OɜMMe֮dvo xk| KO.Y]vFzxǞ+x+>TΒ5due]o]nQYv̝n^}Ȳ%ȡ2psgOKϮKlӾTnU>U5€ ֆG #Lvgl\'}]s~fnOYrkUmUg|&[T|;\k&^ޯ(ܤMڕ%2wS\|9Bߡu9s ^֭j65~3cyf]{3:IϛѿȔͽvrXF}s_N3/!  я@A?| MW ׃ĉeIriѢxaѬg    @GOʔ*Q+(օhwa6 */XYҦ`v!5+VϧCfkٶNPV:wCkՔ_ HױV%U4ޠO~>uB2d,eˑˮGuژ5+ Zt,:s%#|)?/2+K %_||'hO<@4{~#HۍJ-w~0[] {?-9W^w9rIf{S@gro p\o9trHkߛO({êvÄ_PpoA(]<\TVӼ]NoG{of:qb 8   (Y^=w]_d]>unb[dw_ǟ''OH,1,T!y5ǰMZrڵ6ݷ.ߔ% f5?u3yȶ78*VXyo\n#*;A#ej1Dr!QfǠ_T֫azٹpo݇xCMB_*s@@+Шi{~viJ½G OT;qWnJֆ=\ڮ{V>sY4;Z3|8ٺ,ΝckV1ss׭vx/kB!%ND>^>Vl,ohF54hSl6뚉:}Nϕ';c̓l ? Xo{BypzPŠǑl盷ovpizm HV+v׳uݹAXq.](׹C?4{LDz<~l]>]b%:@@@:KV~3m^5C4[pڧ\G-JϕǎuD.D__tDG}$ӭuHJBElG_BuDy 6" /a/w} "pKoD6M˾EٲJ/ʀՀܺi}_-)џ}$Sokp{]E,>=VVAELV=:E@@)y"tboٷ6os涛g#R0~ ϴl'}fvW6kW{=/Ǯ^v_j̞}t(t}uʓ?ͮNtzȡ%&& @J _ 7 ,kf|1(!džV~m}3_%Amsm_7g:l/n/|v   #vq#SҤMgw"SUxpυ]۷e#M&=G.8oTU 6Zf[#}/%ӶvkrYovۉGzRu* ˁs 7]oL#9r;|CKEΝ=-˗,0eˑS?B85wv\Qɔ9| x/sHT'~m[}A$ k?->&I$u֭~9Ytlsh&[7%OR|eiԴU4ךJTD?~|]ѷjPӠWFgW57[U)]bݬ\e9\u~K!1eK湆5>9ud̘Y*=T{I}{@@bFF(ݠbGW\дuֻs704tC kv%/wuwPj\/-طZJ S̴Pmv-zۻ=)R)u=֗z Ηuڳkݬ@@ >~'e+V]갶&c94Xm`b>K.m~-j`y耾v{o; [;mwbo*&5A z% ț(>:Ԛ>9D^!ilc~i[:Mo{Zu~.AMkWˑC員mVeԧMu_IgZn{wޯh 2ӏۉMھi:*(m׵sD k2wt4q"Pf@@@  Rs$ 6G/Zey+W.KP~g吺ʜ]dԮ8Ĝ{v>3YϗL-;z/VfNQ}i36ϙڮ{6]a3}}XSJl6_W-6*zg'Dg@Ms r7{]v=\>~Oض:47aDzD+[7mz˔Սh};g>L[ >{ *[s076}:id mC*ր8._1G;9Ĝ hi^Z_\w2t*MKd&:oU4k>E[\s,[e5܂%J5>Vl L   Č@)HEVYYɳ|[n?s{tob?˶ޞ=fL~Ҁ9sO[9mQΐ>C>~!8U4n/]2! UgϬhTj_O$빫g5u yVwEZ#~#]Zv  *@r~7-W)P0V`vLJ4iaf[3SjȔn<`L[7,M}^&LdnQ{X5JtG|-O*>b}5]q I,9~eOˑCׄ9t@@@ Bg *T&G]C>\@~1)BljJ'is>2;Y[7&:Nĉe٢927CJ7G5c}*\ɾ:Yh}_CJUSrgUMW_n)Ͽ<'ЫW,٬|1I&$MjhƩN@IDAT/F>i XGR-|סKOS9P/ 7lҬ{G3^/ؿ|G|E @ X??ѓ !ˬ)KxwZtÙ) ;GYڴ.odg|-AǗ/. j\9^lnf{Va ik:-۷m6ehlayv?WPiNz״ǏS@@@ &=4: ae!c+xk:mzy=lg.ύM[-v/Yƪejc'J|-luau,,F~DӭϘ9M~P~~pEۏKt^3-?|;a=Nu\sYB-nu36tJO`-՟:  ) ~AD14k8zCpvyf[%qV|HEcOBc?L}ۨR΃K~.Mq65ۤuNޯp:f:o%"ŏlO8&ߺݮCW)U̵[ 5ЯV?At*:/u@A@G{FMfS ܾվK} s8[6ZR\eYq9]x){3Vߒ_Y9u򘽚O;xgZ}<+k6پm&{Uj:?Uԭw峦h5,`0b7Z~9uݧevݳ?xXI}^ + m^dȅ\C36&LȳYH# qXrt@H 7{mXwő[ÊU5j1dwч`L#gn{="5C8eYv׺a?% q.9 ,`gрFIfݳڵ]XG@@@@b]X' -5vв^*Οs˲uf:Y^uEiZƱsjg`ZoRާSMv.mê ެsUY?{g͞mޭ/JYSN*`;xTÑ;}n 1C 6Z4몥pzbtiش     } |_9) N8X{[ ֆWiV9?sXsK79]O6]wV KrEҤM'oj6[Cs ;Oì\@,cwu [k|ܾu m|YkwIh/?*A{vo,gpV۷k6-'ĉtk]u {5xlp㌂    o¾G@! ȕt =ͭz`9캳/'Ž9PܛCv[8աWaGメS~7o۶9έY:UX_WHf|8/\8o~1Ym2)7ȟ^ڶkov۝ jz/[7o3oÑk6C:c5oު-C T@@@%Ϯ@ˑ7c@Mc-_ٮGrʕlC9[m&iJ%yYXckԇ𵿮V Lk`TE;vie{ug GW_ [5GZɝ;> ڳ]muŊsfJgZޣUԷ{6֪tď_ÑҤ3}];_C&5mݤ@ KLϟ .Oow{wv!CKҤIv .Pt//" ,DZ/EoM7+s5*ŚX;{TR]gy$Ö-_mCdӍہAߐIHEWWK͑a߱{C$Kl5lS'vGs M}Е̶v *;I%JvUH;N훛r<ıl\mlбKɺ eg͚ޛIC<)Sm[pem;<^i3vvfX:"ZY<9Dt2fwk`]A{vnmw 3[˗СCrP04x4"E -l='JW.@@/(M IJXt &p5ukyT<3?ȝ)Y%Jq X-a Ž5U< e[ݬn//rws{aK[wk}Ȟufn \5R6wP&&@&cNG##hݽuFsy E6$nY=S@8u >|7E-9rB XrC@@@h X;# s'_ `7ncp_z^bU\2icUxĮ{VvﰛimL>L2y9ήJG.ߔUj8e_nV+ 9sjՑz 4 3ZW{5Y}{wE *b$ET2e!kfi'tdݷxɻ8hyv_EgyL~#qI@_ vʕ(RT$unmn%L7nܐg˹s캶{;tg9rxbM:Lҭ/+   DG kX9"ļ%(+K'!p5Yv|\s<ʝ_4c66I|]gN-svJ%:wsض̓9˃Íp]WD.Ȏ[̜̙2gqO废QD\lMvr쮥Dr,Y\}P`-r9yb^U)!.];venHߺ|5W9slٲ P 48q˜ڵԶʃ>"\bEI6mx+nnx) W#|Z:" +W}^&gʜUt񅢙UZs&G$H VVxT~ p@~SLimZ2d3g|Qlf],-[4rpa#c4i7nKWSI/@MG3 aXM   @d4ZkY`*THyH`rΜ9H"=f,O8Q~G?}tE3,fo{@@@ *  "5k֘ o&zŋlȈ E <˺&AM60~GD@@8,@`9y\:  Įig#k y޽^/lٲfd++9k֬^ш@ &ziɓ' ٳ&;P@p   ',ljD@@!pAY|^w2$H`*T3e  ]y梋f[d? 0hE@@9@@@g4$.%Yd&\bE;+9C XGH TREtqm6Ɏ#@@@{%ﶫܫs\@ QJl%k ]reyb^U)o`ܴܥluY&M*իWwJN. unݲ3ϟv&MH˖-qn }Zrd}ˋBQ1d@ . xX+6W\f/d,vN-p I4YV@H@9s?ݒOދf"[doYɅ 5j~fɒ'BǏ/=Y0ٗ/_flӽڰDsi@ͺN]~"qNrʸ`ISVG@ JT]']d߿?0-[eˆ~   )@`9L6"  / :uJ,X :5KY&Mja^ddu[pĉ+Wʉ'?6K6mLLA@@y@@bYѣ2|P֠ݮ@I$Ydq @)Cf;w=L*|fiܸ 0׫W/p[@@@ Ǯ   po4YȺhPʕ+ŋ'O>H&+٦u]z!~Y.^(3f0KZLE{   )@`Su@@/{챃Pq}%ڵk~˗FOTRK׮]eܸq&|qYpYFiڵ w8#  )@`9 vn@@ؾ}h"J,H`r\ܶDV 2p@` f 2ɯjg9uԑ=<@@@ _/7  lڴL^|ܨDlٲmg 7ߔW_}"[nںut]>3i߾b   [@@qu֙uk t4i؁d;Y>@ 6e .;̫V;c:< *9@@@ _   @Xz~zɐ!ۜɺNAu:ub7o:uJ "!˖-{?/s#  M}  ҥK`-[nP35#Z3) 4kLtì+WȨQҦMQ]:׃  S#  7osIl3i߾ 5kրqF@@@[ @@,kS˞=<#ҷo_)Vu7n4?ڵKl"'Oͮ(PCyRL 6LmfW\xf5 >\cJ˖-M#t74hA4i  AvEV[2@ n<رcMeңG/.ɒ%7U"  _ Ļ*~yg FO(AgɊyVP U^x]j:ǛݶY+ӦM&MXS3uz˭ۊGmS̛7n CRfMYtj7nXe{ fo޼=ϿT%' K`޴i}:59iҤv; x#r@ q[@?׾ZPYO˗5}6m*.\Ъ]>u!C_|afNT?&COȦ q]`Tv޳f9k` 4Y/nn`ǎkIrK׮]{7#  @ >.fފ_E,X[0a~u߿nUt.]H*U&әl7FXF @?x`. ۻC5j ಾDA{ $N:Ɇ 嚱E4gE  ĆP |ry9rK{7ܹsf>Yf97Ν;6M3EdȑffYV\\RurYYlݻWto: gNOzwne>֭[2c8 @'N,]v5#F_ݺuylٲ2zhaԞĞA~H/C寿r4}y7omg%:\5)   $ }[@I@3TvmԞ={nq?w4h 2e+Y;9s:UzY?rhx"RLeoN7vYtog9Q͖nekhl-/ EXCb;籏Eɓ'ݻˋ/(cƌ1x߾}e_9umJ VFydϬ֭3u%mۊ)orh1왭yiG#3V q[ cƌҷo_;O?'vΜ9fy饗LH"qFPx%M4vܹs wfܳsW[%gΜVO@@/Є ]hSަ.Ҡ.:JY:̝;WzA_ Ze?]>cgHީS'4i{%3g4Af:3Э֮]k xǏw[Qe7V@@w! Mu}{Yf̘!ǎ3M[n.]`Հ3@@bG@Yr 0j6 >Һuk;WYbZ`nAekpM62aSנgg}1lٲrMn:ϷgPAm۶A3-ת7juܱc,Y2DPǪP?'  @X ˕+' x׌}nN [V@@"&@rĜ !YAeoŊVO@@EX67@ 2Dtj23D=ztҠA 2ݻd{߷>VN{%XJqi8*}/,hW^M*:gٵk1;vHXGϳgv;>uj?CZE_y)  Q 57B|Z ~zO4=$KmۊͰxb)QD?N!iV$IX]#"u:#  GtHl{W֡hvgnݤr&Go-.[u|Ο?YϞ='u1-a»TÆ sYn]+_~igcΝ=ɑ#Gӛ9ui]4^G˗%C ֪<z~GI.(Qs*  51j  hAxa]… ,˗7sj>Vm۷C=V;wnX6"s{:   UV]td}~,[f"G P߿m}) unYM6LϜ9#R2s[+`g{CϬY͡zeessf͚.Z^j?:\fM;Ogk@p.'O=}M3 @@@ \@ ,}bŊf @@@74@|= jYW_}d2kf+%ݻwZjCRFo[[fk`ٳ&Nd3;I޹sc 5ӾԾ}uRB>| Κ5Kԩ#g϶6 H2eڢ9~˗//_n2=uu}VZuҮ];!C-{X?~@/-Xl]Y\vmkUt}2n8M+ۆV 9m &rc,]TxI2eaNxJס=?;חkA@@ X@@@@"!~&ܴiS˥N:ұcG9p@$FW@@7@@@@?9oN*}?^-j5j{ȑ>;    |9    d/GǏ/ҵkWy'dѢE^ @@%y@@@@$mڴ2h `nذYxԪUK^}U9|0J   }K@@@@@T̜9Sƍ' 6T^ݴ   |Ώ    ` kd/۴@_xǥbŊ2|pecر3gN_d@@8)@`9N~m\4  !tNe˚s~:پtƍqF؍Ug. pΓ'gW@U)Re 0]hC@ Buֵ^4h٧[n2m42ed͚5Bǡ   ̟@@f}Rf}=|,hgrJClʕ+JA@_=!CL󫯾jzmz<+   P`hF@@1]tmrάgY:$,]lzos:kfZS@O sG5kȊ+̥3ow  @$,G   po$I"E139rkYgΜqE3uY~[$Nm^gͮ`s9̒-[Ѐ ?71b4~5VbA@@{$@`rX@@Y+[zֹs9;,sN8ۭzx 3gɒ' @9nK.'l .@@ ޜ 5ۑ>\Z/*Y\7nܐ7o&L( $שľ;ܾw,mڴ!e7L2f<{mNgkmYÇyVpv3f܅:  4kLFOW%!  {};@h hVѢEtrɺu̾;vyi۶|zt5S7JPYyb^U)ch׭ٲe˺mJr:ud޼yq=URJ%#ƍ'OZ]>ylM<[y7ov\ M4ZҦM붹f͚tR?4b U4ȻyݳgJNdҤIX9s 2{nЬa <;ݞ}t=QC\  k?.}Qhv=W\}@l慎9;#H֗*}nM6@cb^7 @ <8{ŋ2aiݺ)eӦM&*1t˗ 1gΜ066jd#kUt̒%KZa~]} * e.!#Q2,(F 6[unϢs[hI&5簂΀<aiG/Cb[Y[&٩A@@ s i$a*u]e K.I=B… fHmgB/gϞfuLaunUVAe_aGW^" yٲe ,kֶR\9g6/lsӆ @Dt(k]tӧ̈́acǎ%~޶%Nkhg`ڪH!iC8&`͵e`Mv@@&@`9jn9 Vɞ={ 48ۻ;\w2uȔה~X!d̲D4(bY9)b,U?M ,Q)BV{>|{u:{?k><+X<šZr-m=o;s:RggSO=<)I [1n+t>N*m~r~K.i-K-TϛoYΫ\Iy :~Ţ.Z̜9U<Їh@k12Dk׷՗.Un4iRHL 8Jɓ{ 0JF-=3i$e*tIdxJ:,jl׿Zy_:*- K -~TL)Q7Ͽ?mW3jN-L[ջmZk5Uey)U&@X ;>"h:RVZir=A3f$~*W]uUX~vZ$SN-8b=lM@6s*.BF_xᅭ*gy[~ [[AT~o p'mhUs 0u^#H{d2{ghy 0^%<rHNzXkiXn*-u>#u>OrF*I,,#8kS6^߫mݭvnTGVwF>-܈ δlr ͺj׶nԫ]`dBl];H @&}nMZzf,]_r%<~P(6P9Z5*xbwtdrcjKW]@ @`X|2Ƭ.--HL*I]ͯ:S?_go(^cBԙgUIvzJV[{Uee} @tXF&/vݱ-2z(oV!@k۬X8:!)7d"#3ytQ]񩧞ڮWhu\ @' (N駟.QPo7xbƫ=Ās?/46sϕSeіdYHtfI?|#=HK:xu{GjtGFX`7qm%@PG?Q׻;:]t2=e5pn۾|Rl4̕om=أ{lf/:#*+rۦ~m=+[zW,>7pCnwL @ .pJ?O *I3({碋.?~z*s.)Ǹ+wƌŗm,LQy_u]ǻeʁ-?o朙BiŤIőGYzr9fIg<ünIK9_**Kx.{YE!?ʑ^xa1u2?]1̩_}q=lA| mUNJb֫,kvjIEV%י$(|]wUI՝y"]oG`2s&@ 07d_>[PѝwYz뭭3]do7yCm˚'.~{b9ϴi:: wolXzoǻo~">촛,Mꫯ;&٠|+M7T:N@9]/yi>guVqǗmV/lя~^5˗ַqeSO=;Nױ*H֯ӧwdʳ'2_jqWlMy;oΓBr??WO9N =O<IJrFv ~>ٰ뗽1$?o_~׍f9s@1ќ9)n| /P_^2b{u-F  @LtC@y{SN鵩O`/A*CR8dgJw[pؙsW{@%Qpi=Ev#롔wܱxzG}Xs5{n,QgԾ[~'m*7Xy睋ǃ5+1KG٠;TZUb[lE޿/ˬ]mnůͦvZ: Ч}\6d~TȜIUg^ZUsۆ|ݪG\Tiu'W5U\/_|eJ.I׫$m]hu @&`gw@974P(Hρڏd[325tXIկzG3#Toywq:/~"ϭQ͠rO9lQQE[,'mtw?m.yxs潰9Q[:|sm]1s̎N5c=3 =%S _踅7޸XuU_We F~n @ 3s69ڶi2ykM=kwI'umR*'^/IVW*TGKb2DzL @` 0r7$hKޣ26&cTr '9眎`k*%]r޳2C=T4r/t[㤶峟lGhn4K~:$@m$LpΈzɻozո-'՗9IdhKT%5zF$u⋋6Sّk} @}$ G˥ @`顛^?B]+hpnEYLu77'`"veL'ȜwNzt]mV[mճ?_੧=GA͒QmQzH@uv^L3p/;[:f[l~0۫4 JdOzlO\sM9*7FCrܳ${n,oIf袋U]u2٠Y<,ƫRy䑪N;/ܭKj$yF6 @}! E @ @dktMhz1z zezhos[F>*ʽxbwtdr}rKWGX^y{<+%䑔zn=il @}' w @ @N{.w/vmjr˵ͣ\'usR9m2tV;#|R|g:N̽ܭdp=-tfW]r7KC4MRվۈj@Iޫdz/Ϲoqn՛v]^ve֧R 46 @XG  @ @vdw};㎎jhcobhvbcaT|mc/o h{uzZ2sKgjUUqgP*i[Jj|V\VF?K/vX ,O:-~o{7{ @ @@ \m@™^6lj榮{WIimNݵ^hVڹ9b6Y]w4 ^vemor蜫L2xt ,y?sw_P+A9sfqv+uZ۶L>.)gTy:묶6V @)`| @ @` lʼn'X2[@o)}EgqF /o7)~buiJs+(vub/|Ǩ~uڤg>cZYg}^x z>šڶ=#]wݶZY`]v٥?of9:Tp vIz g[n)6hbڴiŻ;l;DQu:aN8=O|e")#ītkG  @XM @ @  *7閫ϾK|n🕓O>[o2E}:F .`w#\5?Q->@QGj\8ӋpgWI8)%\Rӫ|_iI^O1wy-3uN X*niڬ@RaOV @ @,2ŵ^ۖ^:3:9#ZyN꺹tM ^_lUerPJI=s(MǬMW_='\Oe>k ;IۮGQyV[mVk#HqUWӽک'@&x @ @顛[K1n#3xUWmV,"M71ҷ0'xL6yfՐmeZPn̟|뭷_|qsSqgr#h5rnn`ﯪom6ų>[^Ugc3{8% ּ1I]:ےzX. @ @ @C`qR$@ ?  @ 0b_## @\ < ../ require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrgen v0.0.0-00010101000000-000000000000 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/tools v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/go.sum000066400000000000000000000026051443314701600261050ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/instrgen_test.go000066400000000000000000000065351443314701600301770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !windows package main import ( "bytes" "fmt" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" alib "go.opentelemetry.io/contrib/instrgen/lib" ) var testcases = map[string]string{ "./testdata/basic": "./testdata/expected/basic", "./testdata/selector": "./testdata/expected/selector", "./testdata/interface": "./testdata/expected/interface", } var failures []string func inject(t *testing.T, root string, packagePattern string) { err := executeCommand("--inject-dump-ir", root, packagePattern) require.NoError(t, err) } func Test(t *testing.T) { for k, v := range testcases { inject(t, k, "./...") files := alib.SearchFiles(k, ".go_pass_tracing") expectedFiles := alib.SearchFiles(v, ".go") numOfFiles := len(expectedFiles) fmt.Println("Go Files:", len(files)) fmt.Println("Expected Go Files:", len(expectedFiles)) numOfComparisons := 0 for _, file := range files { fmt.Println(filepath.Base(file)) for _, expectedFile := range expectedFiles { fmt.Println(filepath.Base(expectedFile)) if filepath.Base(file) == filepath.Base(expectedFile+"_pass_tracing") { f1, err1 := os.ReadFile(file) require.NoError(t, err1) f2, err2 := os.ReadFile(expectedFile) require.NoError(t, err2) if !assert.True(t, bytes.Equal(f1, f2)) { fmt.Println(k) failures = append(failures, k) } numOfComparisons = numOfComparisons + 1 } } } if numOfFiles != numOfComparisons { fmt.Println("numberOfComparisons:", numOfComparisons) panic("not all files were compared") } _, err := Prune(k, "./...", false) if err != nil { fmt.Println("Prune failed") } } for _, f := range failures { fmt.Println("FAILURE : ", f) } } func TestCommands(t *testing.T) { err := executeCommand("--dumpcfg", "./testdata/dummy", "./...") require.NoError(t, err) err = executeCommand("--rootfunctions", "./testdata/dummy", "./...") require.NoError(t, err) err = executeCommand("--prune", "./testdata/dummy", "./...") require.NoError(t, err) err = executeCommand("--inject", "./testdata/dummy", "./...") require.NoError(t, err) err = usage() require.NoError(t, err) } func TestCallGraph(t *testing.T) { cg := makeCallGraph("./testdata/dummy", "./...") dumpCallGraph(cg) assert.Equal(t, len(cg), 0, "callgraph should contain 0 elems") rf := makeRootFunctions("./testdata/dummy", "./...") dumpRootFunctions(rf) assert.Equal(t, len(rf), 0, "rootfunctions set should be empty") } func TestArgs(t *testing.T) { err := checkArgs(nil) require.Error(t, err) args := []string{"driver", "--inject", "", "./..."} err = checkArgs(args) require.NoError(t, err) } func TestUnknown(t *testing.T) { err := executeCommand("unknown", "a", "b") require.Error(t, err) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/main.go000066400000000000000000000130641443314701600262260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "errors" "fmt" "go/ast" "log" "os" alib "go.opentelemetry.io/contrib/instrgen/lib" ) func usage() error { fmt.Println("\nusage driver --command [path to go project] [package pattern]") fmt.Println("\tcommand:") fmt.Println("\t\tinject (injects open telemetry calls into project code)") fmt.Println("\t\tinject-dump-ir (injects open telemetry calls into project code and intermediate passes)") fmt.Println("\t\tprune (prune open telemetry calls") fmt.Println("\t\tdumpcfg (dumps control flow graph)") fmt.Println("\t\trootfunctions (dumps root functions)") return nil } func makeAnalysis(projectPath string, packagePattern string, debug bool) *alib.PackageAnalysis { var rootFunctions []alib.FuncDescriptor interfaces := alib.FindInterfaces(projectPath, packagePattern) rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern, "AutotelEntryPoint")...) funcDecls := alib.FindFuncDecls(projectPath, packagePattern, interfaces) backwardCallGraph := alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) fmt.Println("\n\tchild parent") for k, v := range backwardCallGraph { fmt.Print("\n\t", k) fmt.Print(" ", v) } fmt.Println("") analysis := &alib.PackageAnalysis{ ProjectPath: projectPath, PackagePattern: packagePattern, RootFunctions: rootFunctions, FuncDecls: funcDecls, Callgraph: backwardCallGraph, Interfaces: interfaces, Debug: debug} return analysis } // Prune. func Prune(projectPath string, packagePattern string, debug bool) ([]*ast.File, error) { analysis := makeAnalysis(projectPath, packagePattern, debug) return analysis.Execute(&alib.OtelPruner{}, otelPrunerPassSuffix) } func makeCallGraph(projectPath string, packagePattern string) map[alib.FuncDescriptor][]alib.FuncDescriptor { var funcDecls map[alib.FuncDescriptor]bool var backwardCallGraph map[alib.FuncDescriptor][]alib.FuncDescriptor interfaces := alib.FindInterfaces(projectPath, packagePattern) funcDecls = alib.FindFuncDecls(projectPath, packagePattern, interfaces) backwardCallGraph = alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) return backwardCallGraph } func makeRootFunctions(projectPath string, packagePattern string) []alib.FuncDescriptor { var rootFunctions []alib.FuncDescriptor rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern, "AutotelEntryPoint")...) return rootFunctions } func dumpCallGraph(callGraph map[alib.FuncDescriptor][]alib.FuncDescriptor) { fmt.Println("\n\tchild parent") for k, v := range callGraph { fmt.Print("\n\t", k) fmt.Print(" ", v) } } func dumpRootFunctions(rootFunctions []alib.FuncDescriptor) { fmt.Println("rootfunctions:") for _, fun := range rootFunctions { fmt.Println("\t" + fun.TypeHash()) } } func isDirectory(path string) (bool, error) { fileInfo, err := os.Stat(path) if err != nil { return false, err } return fileInfo.IsDir(), err } // Parsing algorithm works as follows. It goes through all function // decls and infer function bodies to find call to AutotelEntryPoint // A parent function of this call will become root of instrumentation // Each function call from this place will be instrumented automatically. func executeCommand(command string, projectPath string, packagePattern string) error { isDir, err := isDirectory(projectPath) if !isDir { _ = usage() return errors.New("[path to go project] argument must be directory") } if err != nil { return err } switch command { case "--inject": _, err := Prune(projectPath, packagePattern, false) if err != nil { return err } analysis := makeAnalysis(projectPath, packagePattern, false) err = ExecutePasses(analysis) if err != nil { return err } fmt.Println("\tinstrumentation done") return nil case "--inject-dump-ir": _, err := Prune(projectPath, packagePattern, true) if err != nil { return err } analysis := makeAnalysis(projectPath, packagePattern, true) err = ExecutePassesDumpIr(analysis) if err != nil { return err } fmt.Println("\tinstrumentation done") return nil case "--dumpcfg": backwardCallGraph := makeCallGraph(projectPath, packagePattern) dumpCallGraph(backwardCallGraph) return nil case "--rootfunctions": rootFunctions := makeRootFunctions(projectPath, packagePattern) dumpRootFunctions(rootFunctions) return nil case "--prune": _, err := Prune(projectPath, packagePattern, false) if err != nil { return err } return nil default: return errors.New("unknown command") } } func checkArgs(args []string) error { if len(args) != 4 { _ = usage() return errors.New("wrong arguments") } return nil } func main() { fmt.Println("autotel compiler") err := checkArgs(os.Args) if err != nil { return } err = executeCommand(os.Args[1], os.Args[2], os.Args[3]) if err != nil { log.Fatal(err) } } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/passes.go000066400000000000000000000030041443314701600265710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "fmt" "go.opentelemetry.io/contrib/instrgen/lib" ) const ( otelPrunerPassSuffix = "_pass_pruner" contextPassFileSuffix = "_pass_ctx" instrumentationPassFileSuffix = "_pass_tracing" ) // ExecutePassesDumpIr. func ExecutePassesDumpIr(analysis *lib.PackageAnalysis) error { fmt.Println("Instrumentation") _, err := analysis.Execute(&lib.InstrumentationPass{}, "") if err != nil { return err } fmt.Println("ContextPropagation") _, err = analysis.Execute(&lib.ContextPropagationPass{}, instrumentationPassFileSuffix) return err } // ExecutePasses. func ExecutePasses(analysis *lib.PackageAnalysis) error { fmt.Println("Instrumentation") _, err := analysis.Execute(&lib.InstrumentationPass{}, instrumentationPassFileSuffix) if err != nil { return err } fmt.Println("ContextPropagation") _, err = analysis.Execute(&lib.ContextPropagationPass{}, contextPassFileSuffix) return err } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/000077500000000000000000000000001443314701600265605ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/000077500000000000000000000000001443314701600276415ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/fib.go000066400000000000000000000021741443314701600307340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" ) func foo() { fmt.Println("foo") } func FibonacciHelper(n uint) (uint64, error) { func() { foo() }() return Fibonacci(n) } func Fibonacci(n uint) (uint64, error) { if n <= 1 { return uint64(n), nil } if n > 93 { return 0, fmt.Errorf("unsupported fibonacci number %d: too large", n) } var n2, n1 uint64 = 0, 1 for i := uint(2); i < n; i++ { n2, n1 = n1, n1+n2 } return n2 + n1, nil } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/goroutines.go000066400000000000000000000015471443314701600323750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" ) func goroutines() { messages := make(chan string) go func() { messages <- "ping" }() msg := <-messages fmt.Println(msg) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/main.go000066400000000000000000000016771443314701600311270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" "go.opentelemetry.io/contrib/instrgen/rtlib" ) func recur(n int) { if n > 0 { recur(n - 1) } } func main() { rtlib.AutotelEntryPoint() fmt.Println(FibonacciHelper(10)) recur(5) goroutines() pack() methods() } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/methods.go000066400000000000000000000021321443314701600316310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main type element struct { } type driver struct { e element } type i interface { anotherfoo(p int) int } type impl struct { } func (i impl) anotherfoo(p int) int { return 5 } func anotherfoo(p int) int { return 1 } func (d driver) process(a int) { } func (e element) get(a int) { } func methods() { d := driver{} d.process(10) d.e.get(5) var in i in = impl{} in.anotherfoo(10) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/basic/package.go000066400000000000000000000015241443314701600315650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "os" ) func Close() error { return nil } func pack() { f, e := os.Create("temp") defer f.Close() if e != nil { } } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/dummy/000077500000000000000000000000001443314701600277135ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/dummy/main.go000066400000000000000000000013361443314701600311710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main func main() { } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/000077500000000000000000000000001443314701600303615ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/000077500000000000000000000000001443314701600314425ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/fib.go000066400000000000000000000040251443314701600325320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" __atel_context "context" __atel_otel "go.opentelemetry.io/otel" ) func foo(__atel_tracing_ctx __atel_context.Context,) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("foo").Start(__atel_tracing_ctx, "foo") _ = __atel_child_tracing_ctx defer __atel_span.End() fmt.Println("foo") } func FibonacciHelper(__atel_tracing_ctx __atel_context.Context, n uint) (uint64, error) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("FibonacciHelper").Start(__atel_tracing_ctx, "FibonacciHelper") _ = __atel_child_tracing_ctx defer __atel_span.End() func() { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("anonymous").Start(__atel_child_tracing_ctx, "anonymous") _ = __atel_child_tracing_ctx defer __atel_span.End() foo(__atel_child_tracing_ctx) }() return Fibonacci(__atel_child_tracing_ctx, n) } func Fibonacci(__atel_tracing_ctx __atel_context.Context, n uint) (uint64, error) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("Fibonacci").Start(__atel_tracing_ctx, "Fibonacci") _ = __atel_child_tracing_ctx defer __atel_span.End() if n <= 1 { return uint64(n), nil } if n > 93 { return 0, fmt.Errorf("unsupported fibonacci number %d: too large", n) } var n2, n1 uint64 = 0, 1 for i := uint(2); i < n; i++ { n2, n1 = n1, n1+n2 } return n2 + n1, nil } goroutines.go000066400000000000000000000024541443314701600341150ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" __atel_context "context" __atel_otel "go.opentelemetry.io/otel" ) func goroutines(__atel_tracing_ctx __atel_context.Context,) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("goroutines").Start(__atel_tracing_ctx, "goroutines") _ = __atel_child_tracing_ctx defer __atel_span.End() messages := make(chan string) go func() { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("anonymous").Start(__atel_child_tracing_ctx, "anonymous") _ = __atel_child_tracing_ctx defer __atel_span.End() messages <- "ping" }() msg := <-messages fmt.Println(msg) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/main.go000066400000000000000000000032231443314701600327150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "fmt" __atel_context "context" "go.opentelemetry.io/contrib/instrgen/rtlib" __atel_otel "go.opentelemetry.io/otel" ) func recur(__atel_tracing_ctx __atel_context.Context, n int) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("recur").Start(__atel_tracing_ctx, "recur") _ = __atel_child_tracing_ctx defer __atel_span.End() if n > 0 { recur(__atel_child_tracing_ctx, n-1) } } func main() { __atel_ts := rtlib.NewTracingState() defer rtlib.Shutdown(__atel_ts) __atel_otel.SetTracerProvider(__atel_ts.Tp) __atel_ctx := __atel_context.Background() __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") _ = __atel_child_tracing_ctx defer __atel_span.End() rtlib.AutotelEntryPoint() fmt.Println(FibonacciHelper(__atel_child_tracing_ctx, 10)) recur(__atel_child_tracing_ctx, 5) goroutines(__atel_child_tracing_ctx) pack(__atel_child_tracing_ctx) methods(__atel_child_tracing_ctx) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/methods.go000066400000000000000000000041311443314701600334330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( __atel_context "context" __atel_otel "go.opentelemetry.io/otel" ) type element struct { } type driver struct { e element } type i interface { anotherfoo(__atel_tracing_ctx __atel_context.Context, p int) int } type impl struct { } func (i impl) anotherfoo(__atel_tracing_ctx __atel_context.Context, p int) int { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("anotherfoo").Start(__atel_tracing_ctx, "anotherfoo") _ = __atel_child_tracing_ctx defer __atel_span.End() return 5 } func anotherfoo(p int) int { return 1 } func (d driver) process(__atel_tracing_ctx __atel_context.Context, a int) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("process").Start(__atel_tracing_ctx, "process") _ = __atel_child_tracing_ctx defer __atel_span.End() } func (e element) get(__atel_tracing_ctx __atel_context.Context, a int) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("get").Start(__atel_tracing_ctx, "get") _ = __atel_child_tracing_ctx defer __atel_span.End() } func methods(__atel_tracing_ctx __atel_context.Context,) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("methods").Start(__atel_tracing_ctx, "methods") _ = __atel_child_tracing_ctx defer __atel_span.End() d := driver{} d.process(__atel_child_tracing_ctx, 10) d.e.get(__atel_child_tracing_ctx, 5) var in i in = impl{} in.anotherfoo(__atel_child_tracing_ctx, 10) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/package.go000066400000000000000000000021351443314701600333650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "os" __atel_context "context" __atel_otel "go.opentelemetry.io/otel" ) func Close() error { return nil } func pack(__atel_tracing_ctx __atel_context.Context,) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("pack").Start(__atel_tracing_ctx, "pack") _ = __atel_child_tracing_ctx defer __atel_span.End() f, e := os.Create("temp") defer f.Close() if e != nil { } } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/basic/traces.txt000066400000000000000000000056261443314701600334750ustar00rootroot00000000000000{ "Name": "foo", "SpanContext": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "8c982b3e435c56e0", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "65c37661e2869798", "TraceFlags": "01", "TraceState": "", "Remote": false }, "SpanKind": 1, "StartTime": "0001-01-01T00:00:00Z", "EndTime": "0001-01-01T00:00:00Z", "Attributes": null, "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 0, "Resource": null, "InstrumentationLibrary": { "Name": "foo", "Version": "", "SchemaURL": "" } } { "Name": "Fibonacci", "SpanContext": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "6676950f24fe09e2", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "65c37661e2869798", "TraceFlags": "01", "TraceState": "", "Remote": false }, "SpanKind": 1, "StartTime": "0001-01-01T00:00:00Z", "EndTime": "0001-01-01T00:00:00Z", "Attributes": null, "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 0, "Resource": null, "InstrumentationLibrary": { "Name": "Fibonacci", "Version": "", "SchemaURL": "" } } { "Name": "FibonacciHelper", "SpanContext": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "65c37661e2869798", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "89a2f3b8fc474d6a", "TraceFlags": "01", "TraceState": "", "Remote": false }, "SpanKind": 1, "StartTime": "0001-01-01T00:00:00Z", "EndTime": "0001-01-01T00:00:00Z", "Attributes": null, "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 2, "Resource": null, "InstrumentationLibrary": { "Name": "FibonacciHelper", "Version": "", "SchemaURL": "" } } { "Name": "main", "SpanContext": { "TraceID": "374c11217817c32b01876bb2e2aceae8", "SpanID": "89a2f3b8fc474d6a", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "00000000000000000000000000000000", "SpanID": "0000000000000000", "TraceFlags": "00", "TraceState": "", "Remote": false }, "SpanKind": 1, "StartTime": "0001-01-01T00:00:00Z", "EndTime": "0001-01-01T00:00:00Z", "Attributes": null, "Events": null, "Links": null, "Status": { "Code": "Unset", "Description": "" }, "DroppedAttributes": 0, "DroppedEvents": 0, "DroppedLinks": 0, "ChildSpanCount": 1, "Resource": null, "InstrumentationLibrary": { "Name": "main", "Version": "", "SchemaURL": "" } } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interface/000077500000000000000000000000001443314701600323215ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interface/app/000077500000000000000000000000001443314701600331015ustar00rootroot00000000000000impl.go000066400000000000000000000021311443314701600343070ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interface/app// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package app import ( "fmt" __atel_context "context" __atel_otel "go.opentelemetry.io/otel" ) type BasicSerializer struct { } func (b BasicSerializer) Serialize(__atel_tracing_ctx __atel_context.Context,) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("Serialize").Start(__atel_tracing_ctx, "Serialize") _ = __atel_child_tracing_ctx defer __atel_span.End() fmt.Println("Serialize") } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interface/main.go000066400000000000000000000026161443314701600336010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( . "go.opentelemetry.io/contrib/instrgen/testdata/interface/app" __atel_otel "go.opentelemetry.io/otel" __atel_context "context" . "go.opentelemetry.io/contrib/instrgen/testdata/interface/serializer" "go.opentelemetry.io/contrib/instrgen/rtlib" ) func main() { __atel_ts := rtlib.NewTracingState() defer rtlib.Shutdown(__atel_ts) __atel_otel.SetTracerProvider(__atel_ts.Tp) __atel_ctx := __atel_context.Background() __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") _ = __atel_child_tracing_ctx defer __atel_span.End() rtlib.AutotelEntryPoint() bs := BasicSerializer{} var s Serializer s = bs s.Serialize(__atel_child_tracing_ctx) } serializer/000077500000000000000000000000001443314701600344135ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interfaceinterface.go000066400000000000000000000015121443314701600367010ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/interface/serializer// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package serializer import __atel_context "context" type Serializer interface { Serialize(__atel_tracing_ctx __atel_context.Context,) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/selector/000077500000000000000000000000001443314701600322015ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/expected/selector/main.go000066400000000000000000000031741443314701600334610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "go.opentelemetry.io/contrib/instrgen/rtlib" __atel_otel "go.opentelemetry.io/otel" __atel_context "context" ) type Driver interface { Foo(__atel_tracing_ctx __atel_context.Context, i int) } type Impl struct { } func (impl Impl) Foo(__atel_tracing_ctx __atel_context.Context, i int) { __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("Foo").Start(__atel_tracing_ctx, "Foo") _ = __atel_child_tracing_ctx defer __atel_span.End() } func main() { __atel_ts := rtlib.NewTracingState() defer rtlib.Shutdown(__atel_ts) __atel_otel.SetTracerProvider(__atel_ts.Tp) __atel_ctx := __atel_context.Background() __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") _ = __atel_child_tracing_ctx defer __atel_span.End() rtlib.AutotelEntryPoint() a := []Driver{ Impl{}, } var d Driver d = Impl{} d.Foo(__atel_child_tracing_ctx, 3) a[0].Foo(__atel_child_tracing_ctx, 4) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/funwithoutpathtoroot/000077500000000000000000000000001443314701600331205ustar00rootroot00000000000000driver.go000066400000000000000000000015421443314701600346650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/funwithoutpathtoroot// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "go.opentelemetry.io/contrib/instrgen/rtlib" ) func bar() { } func foo() { bar() } func main() { rtlib.AutotelEntryPoint() bar() } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/000077500000000000000000000000001443314701600305205ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/app/000077500000000000000000000000001443314701600313005ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/app/impl.go000066400000000000000000000015051443314701600325710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package app import ( "fmt" ) type BasicSerializer struct { } func (b BasicSerializer) Serialize() { fmt.Println("Serialize") } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/go.mod000066400000000000000000000010741443314701600316300ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrgen/testdata/interface go 1.18 replace go.opentelemetry.io/contrib/instrgen => ../../.. require go.opentelemetry.io/contrib/instrgen v0.0.0-20221228173227-92e0588b124b require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel v1.15.1 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 // indirect go.opentelemetry.io/otel/sdk v1.15.1 // indirect go.opentelemetry.io/otel/trace v1.15.1 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/go.sum000066400000000000000000000032731443314701600316600ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 h1:2PunuO5SbkN5MhCbuHCd3tC6qrcaj+uDAkX/qBU5BAs= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1/go.mod h1:q8+Tha+5LThjeSU8BW93uUC5w5/+DnYHMKBMpRCsui0= go.opentelemetry.io/otel/sdk v1.15.1 h1:5FKR+skgpzvhPQHIEfcwMYjCBr14LWzs3uSqKiQzETI= go.opentelemetry.io/otel/sdk v1.15.1/go.mod h1:8rVtxQfrbmbHKfqzpQkT5EzZMcbMBwTzNAggbEAM0KA= go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY= go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/main.go000066400000000000000000000017771443314701600320070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( . "go.opentelemetry.io/contrib/instrgen/testdata/interface/app" . "go.opentelemetry.io/contrib/instrgen/testdata/interface/serializer" "go.opentelemetry.io/contrib/instrgen/rtlib" ) func main() { rtlib.AutotelEntryPoint() bs := BasicSerializer{} var s Serializer s = bs s.Serialize() } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/serializer/000077500000000000000000000000001443314701600326715ustar00rootroot00000000000000interface.go000066400000000000000000000013771443314701600351110ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/interface/serializer// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package serializer type Serializer interface { Serialize() } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/selector/000077500000000000000000000000001443314701600304005ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/driver/testdata/selector/main.go000066400000000000000000000017411443314701600316560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //nolint:all // Linter is executed at the same time as tests which leads to race conditions and failures. package main import ( "go.opentelemetry.io/contrib/instrgen/rtlib" ) type Driver interface { Foo(i int) } type Impl struct { } func (impl Impl) Foo(i int) { } func main() { rtlib.AutotelEntryPoint() a := []Driver{ Impl{}, } var d Driver d = Impl{} d.Foo(3) a[0].Foo(4) } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/go.mod000066400000000000000000000007101443314701600245600ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrgen go 1.19 require ( go.opentelemetry.io/otel v1.15.1 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 go.opentelemetry.io/otel/sdk v1.15.1 golang.org/x/tools v0.9.1 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/trace v1.15.1 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrgen/go.sum000066400000000000000000000040701443314701600246100ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 h1:2PunuO5SbkN5MhCbuHCd3tC6qrcaj+uDAkX/qBU5BAs= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1/go.mod h1:q8+Tha+5LThjeSU8BW93uUC5w5/+DnYHMKBMpRCsui0= go.opentelemetry.io/otel/sdk v1.15.1 h1:5FKR+skgpzvhPQHIEfcwMYjCBr14LWzs3uSqKiQzETI= go.opentelemetry.io/otel/sdk v1.15.1/go.mod h1:8rVtxQfrbmbHKfqzpQkT5EzZMcbMBwTzNAggbEAM0KA= go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY= go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/000077500000000000000000000000001443314701600242225ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/analysis.go000066400000000000000000000075071443314701600264050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "fmt" "go/ast" "go/printer" "go/token" "os" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/packages" ) // PackageAnalysis analyze all package set accrding to passed // pattern. It requires an information about path, pattern, // root functions - entry points, function declarations, // and so on. type PackageAnalysis struct { ProjectPath string PackagePattern string RootFunctions []FuncDescriptor FuncDecls map[FuncDescriptor]bool Callgraph map[FuncDescriptor][]FuncDescriptor Interfaces map[string]bool Debug bool } type importaction int const ( // const that tells whether package should be imported. Add importaction = iota // or removed. Remove ) // Stores an information about operations on packages. // Currently packages can be imported with an aliases // or without. type Import struct { NamedPackage string Package string ImportAction importaction } // FileAnalysisPass executes an analysis for // specific file node - translation unit. type FileAnalysisPass interface { Execute(node *ast.File, analysis *PackageAnalysis, pkg *packages.Package, pkgs []*packages.Package) []Import } func createFile(name string) (*os.File, error) { var out *os.File out, err := os.Create(name) if err != nil { defer out.Close() } return out, err } func addImports(imports []Import, fset *token.FileSet, fileNode *ast.File) { for _, imp := range imports { if imp.ImportAction == Add { if len(imp.NamedPackage) > 0 { astutil.AddNamedImport(fset, fileNode, imp.NamedPackage, imp.Package) } else { astutil.AddImport(fset, fileNode, imp.Package) } } else { if len(imp.NamedPackage) > 0 { astutil.DeleteNamedImport(fset, fileNode, imp.NamedPackage, imp.Package) } else { astutil.DeleteImport(fset, fileNode, imp.Package) } } } } // Execute function, main entry point to analysis process. func (analysis *PackageAnalysis) Execute(pass FileAnalysisPass, fileSuffix string) ([]*ast.File, error) { fset := token.NewFileSet() cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: analysis.ProjectPath} pkgs, err := packages.Load(cfg, analysis.PackagePattern) if err != nil { return nil, err } var fileNodeSet []*ast.File for _, pkg := range pkgs { fmt.Println("\t", pkg) // fileNode represents a translationUnit var fileNode *ast.File for _, fileNode = range pkg.Syntax { fmt.Println("\t\t", fset.File(fileNode.Pos()).Name()) var out *os.File out, err = createFile(fset.File(fileNode.Pos()).Name() + fileSuffix) if err != nil { return nil, err } if len(analysis.RootFunctions) == 0 { e := printer.Fprint(out, fset, fileNode) if e != nil { return nil, e } continue } imports := pass.Execute(fileNode, analysis, pkg, pkgs) addImports(imports, fset, fileNode) e := printer.Fprint(out, fset, fileNode) if e != nil { return nil, e } if !analysis.Debug { oldFileName := fset.File(fileNode.Pos()).Name() + fileSuffix newFileName := fset.File(fileNode.Pos()).Name() e = os.Rename(oldFileName, newFileName) if e != nil { return nil, e } } fileNodeSet = append(fileNodeSet, fileNode) } } return fileNodeSet, nil } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/callgraph.go000066400000000000000000000317121443314701600265120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "fmt" "go/ast" "go/token" "go/types" "strings" "golang.org/x/tools/go/packages" ) // FuncDescriptor stores an information about // id, type and if function requires custom instrumentation. type FuncDescriptor struct { Id string DeclType string CustomInjection bool } // Function TypeHash. Each function is itentified by its // id and type. func (fd FuncDescriptor) TypeHash() string { return fd.Id + fd.DeclType } // LoadMode. Tells about needed information during analysis. const LoadMode packages.LoadMode = packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedFiles func getPkgs(projectPath string, packagePattern string, fset *token.FileSet) ([]*packages.Package, error) { cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: projectPath} pkgs, err := packages.Load(cfg, packagePattern) var packageSet []*packages.Package if err != nil { return nil, err } for _, pkg := range pkgs { fmt.Println("\t", pkg) packageSet = append(packageSet, pkg) } return packageSet, nil } // FindRootFunctions looks for all root functions eg. entry points. // Currently an entry point is a function that contains call of function // passed as functionLabel paramaterer. func FindRootFunctions(projectPath string, packagePattern string, functionLabel string) []FuncDescriptor { fset := token.NewFileSet() pkgs, _ := getPkgs(projectPath, packagePattern, fset) var currentFun FuncDescriptor var rootFunctions []FuncDescriptor for _, pkg := range pkgs { for _, node := range pkg.Syntax { ast.Inspect(node, func(n ast.Node) bool { switch xNode := n.(type) { case *ast.CallExpr: selector, ok := xNode.Fun.(*ast.SelectorExpr) if ok { if selector.Sel.Name == functionLabel { rootFunctions = append(rootFunctions, currentFun) } } case *ast.FuncDecl: if pkg.TypesInfo.Defs[xNode.Name] != nil { funId := pkg.TypesInfo.Defs[xNode.Name].Pkg().Path() + "." + pkg.TypesInfo.Defs[xNode.Name].Name() currentFun = FuncDescriptor{funId, pkg.TypesInfo.Defs[xNode.Name].Type().String(), false} fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[xNode.Name].Type().String()) } } return true }) } } return rootFunctions } // GetMostInnerAstIdent takes most inner identifier used for // function call. For a.b.foo(), `b` will be the most inner identifier. func GetMostInnerAstIdent(inSel *ast.SelectorExpr) *ast.Ident { var l []*ast.Ident var e ast.Expr e = inSel for e != nil { if _, ok := e.(*ast.Ident); ok { l = append(l, e.(*ast.Ident)) break } else if _, ok := e.(*ast.SelectorExpr); ok { l = append(l, e.(*ast.SelectorExpr).Sel) e = e.(*ast.SelectorExpr).X } else if _, ok := e.(*ast.CallExpr); ok { e = e.(*ast.CallExpr).Fun } else if _, ok := e.(*ast.IndexExpr); ok { e = e.(*ast.IndexExpr).X } else if _, ok := e.(*ast.UnaryExpr); ok { e = e.(*ast.UnaryExpr).X } else if _, ok := e.(*ast.ParenExpr); ok { e = e.(*ast.ParenExpr).X } else if _, ok := e.(*ast.SliceExpr); ok { e = e.(*ast.SliceExpr).X } else if _, ok := e.(*ast.IndexListExpr); ok { e = e.(*ast.IndexListExpr).X } else if _, ok := e.(*ast.StarExpr); ok { e = e.(*ast.StarExpr).X } else if _, ok := e.(*ast.TypeAssertExpr); ok { e = e.(*ast.TypeAssertExpr).X } else if _, ok := e.(*ast.CompositeLit); ok { // TODO dummy implementation if len(e.(*ast.CompositeLit).Elts) == 0 { e = e.(*ast.CompositeLit).Type } else { e = e.(*ast.CompositeLit).Elts[0] } } else if _, ok := e.(*ast.KeyValueExpr); ok { e = e.(*ast.KeyValueExpr).Value } else { // TODO this is uncaught expression panic("uncaught expression") } } if len(l) < 2 { panic("selector list should have at least 2 elems") } // caller or receiver is always // at position 1, function is at 0 return l[1] } // GetPkgPathFromRecvInterface builds package path taking // receiver interface into account. func GetPkgPathFromRecvInterface(pkg *packages.Package, pkgs []*packages.Package, funDeclNode *ast.FuncDecl, interfaces map[string]bool) string { var pkgPath string for _, v := range funDeclNode.Recv.List { for _, dependentpkg := range pkgs { for _, defs := range dependentpkg.TypesInfo.Defs { if defs == nil { continue } if _, ok := defs.Type().Underlying().(*types.Interface); !ok { continue } if len(v.Names) == 0 || pkg.TypesInfo.Defs[v.Names[0]] == nil { continue } funType := pkg.TypesInfo.Defs[v.Names[0]].Type() if types.Implements(funType, defs.Type().Underlying().(*types.Interface)) { interfaceExists := interfaces[defs.Type().String()] if interfaceExists { pkgPath = defs.Type().String() } break } } } } return pkgPath } // GetPkgPathFromFunctionRecv build package path taking function receiver parameters. func GetPkgPathFromFunctionRecv(pkg *packages.Package, pkgs []*packages.Package, funDeclNode *ast.FuncDecl, interfaces map[string]bool) string { pkgPath := GetPkgPathFromRecvInterface(pkg, pkgs, funDeclNode, interfaces) if len(pkgPath) != 0 { return pkgPath } for _, v := range funDeclNode.Recv.List { if len(v.Names) == 0 { continue } funType := pkg.TypesInfo.Defs[v.Names[0]].Type() pkgPath = funType.String() // We don't care if that's pointer, remove it from // type id if _, ok := funType.(*types.Pointer); ok { pkgPath = strings.TrimPrefix(pkgPath, "*") } // We don't care if called via index, remove it from // type id if _, ok := funType.(*types.Slice); ok { pkgPath = strings.TrimPrefix(pkgPath, "[]") } } return pkgPath } // GetSelectorPkgPath builds packages path according to selector expr. func GetSelectorPkgPath(sel *ast.SelectorExpr, pkg *packages.Package, pkgPath string) string { caller := GetMostInnerAstIdent(sel) if caller != nil && pkg.TypesInfo.Uses[caller] != nil { if !strings.Contains(pkg.TypesInfo.Uses[caller].Type().String(), "invalid") { pkgPath = pkg.TypesInfo.Uses[caller].Type().String() // We don't care if that's pointer, remove it from // type id if _, ok := pkg.TypesInfo.Uses[caller].Type().(*types.Pointer); ok { pkgPath = strings.TrimPrefix(pkgPath, "*") } // We don't care if called via index, remove it from // type id if _, ok := pkg.TypesInfo.Uses[caller].Type().(*types.Slice); ok { pkgPath = strings.TrimPrefix(pkgPath, "[]") } } } return pkgPath } // GetPkgNameFromUsesTable gets package name from uses table. func GetPkgNameFromUsesTable(pkg *packages.Package, ident *ast.Ident) string { var pkgPath string if pkg.TypesInfo.Uses[ident].Pkg() != nil { pkgPath = pkg.TypesInfo.Uses[ident].Pkg().Path() } return pkgPath } // GetPkgNameFromDefsTable gets package name from uses table. func GetPkgNameFromDefsTable(pkg *packages.Package, ident *ast.Ident) string { var pkgPath string if pkg.TypesInfo.Defs[ident] == nil { return pkgPath } if pkg.TypesInfo.Defs[ident].Pkg() != nil { pkgPath = pkg.TypesInfo.Defs[ident].Pkg().Path() } return pkgPath } // GetPkgPathForFunction builds package path, delegates work to // other helper functions defined above. func GetPkgPathForFunction(pkg *packages.Package, pkgs []*packages.Package, funDecl *ast.FuncDecl, interfaces map[string]bool) string { if funDecl.Recv != nil { return GetPkgPathFromFunctionRecv(pkg, pkgs, funDecl, interfaces) } return GetPkgNameFromDefsTable(pkg, funDecl.Name) } // BuildCallGraph builds an information about flow graph // in the following form child->parent. func BuildCallGraph( projectPath string, packagePattern string, funcDecls map[FuncDescriptor]bool, interfaces map[string]bool) map[FuncDescriptor][]FuncDescriptor { fset := token.NewFileSet() pkgs, _ := getPkgs(projectPath, packagePattern, fset) fmt.Println("BuildCallGraph") currentFun := FuncDescriptor{"nil", "", false} backwardCallGraph := make(map[FuncDescriptor][]FuncDescriptor) for _, pkg := range pkgs { fmt.Println("\t", pkg) for _, node := range pkg.Syntax { fmt.Println("\t\t", fset.File(node.Pos()).Name()) ast.Inspect(node, func(n ast.Node) bool { switch xNode := n.(type) { case *ast.CallExpr: if id, ok := xNode.Fun.(*ast.Ident); ok { pkgPath := GetPkgNameFromUsesTable(pkg, id) funId := pkgPath + "." + pkg.TypesInfo.Uses[id].Name() fmt.Println("\t\t\tFuncCall:", funId, pkg.TypesInfo.Uses[id].Type().String(), " @called : ", fset.File(node.Pos()).Name()) fun := FuncDescriptor{funId, pkg.TypesInfo.Uses[id].Type().String(), false} if !Contains(backwardCallGraph[fun], currentFun) { if funcDecls[fun] { backwardCallGraph[fun] = append(backwardCallGraph[fun], currentFun) } } } if sel, ok := xNode.Fun.(*ast.SelectorExpr); ok { if pkg.TypesInfo.Uses[sel.Sel] != nil { pkgPath := GetPkgNameFromUsesTable(pkg, sel.Sel) if sel.X != nil { pkgPath = GetSelectorPkgPath(sel, pkg, pkgPath) } funId := pkgPath + "." + pkg.TypesInfo.Uses[sel.Sel].Name() fmt.Println("\t\t\tFuncCall via selector:", funId, pkg.TypesInfo.Uses[sel.Sel].Type().String(), " @called : ", fset.File(node.Pos()).Name()) fun := FuncDescriptor{funId, pkg.TypesInfo.Uses[sel.Sel].Type().String(), false} if !Contains(backwardCallGraph[fun], currentFun) { if funcDecls[fun] { backwardCallGraph[fun] = append(backwardCallGraph[fun], currentFun) } } } } case *ast.FuncDecl: if pkg.TypesInfo.Defs[xNode.Name] != nil { pkgPath := GetPkgPathForFunction(pkg, pkgs, xNode, interfaces) funId := pkgPath + "." + pkg.TypesInfo.Defs[xNode.Name].Name() funcDecls[FuncDescriptor{funId, pkg.TypesInfo.Defs[xNode.Name].Type().String(), false}] = true currentFun = FuncDescriptor{funId, pkg.TypesInfo.Defs[xNode.Name].Type().String(), false} fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[xNode.Name].Type().String()) } } return true }) } } return backwardCallGraph } // FindFuncDecls looks for all function declarations. func FindFuncDecls(projectPath string, packagePattern string, interfaces map[string]bool) map[FuncDescriptor]bool { fset := token.NewFileSet() pkgs, _ := getPkgs(projectPath, packagePattern, fset) fmt.Println("FindFuncDecls") funcDecls := make(map[FuncDescriptor]bool) for _, pkg := range pkgs { fmt.Println("\t", pkg) for _, node := range pkg.Syntax { fmt.Println("\t\t", fset.File(node.Pos()).Name()) ast.Inspect(node, func(n ast.Node) bool { if funDeclNode, ok := n.(*ast.FuncDecl); ok { pkgPath := GetPkgPathForFunction(pkg, pkgs, funDeclNode, interfaces) if pkg.TypesInfo.Defs[funDeclNode.Name] != nil { funId := pkgPath + "." + pkg.TypesInfo.Defs[funDeclNode.Name].Name() fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[funDeclNode.Name].Type().String()) funcDecls[FuncDescriptor{funId, pkg.TypesInfo.Defs[funDeclNode.Name].Type().String(), false}] = true } } return true }) } } return funcDecls } // FindInterfaces looks for all interfaces. func FindInterfaces(projectPath string, packagePattern string) map[string]bool { fset := token.NewFileSet() pkgs, _ := getPkgs(projectPath, packagePattern, fset) fmt.Println("FindInterfaces") interaceTable := make(map[string]bool) for _, pkg := range pkgs { fmt.Println("\t", pkg) for _, node := range pkg.Syntax { fmt.Println("\t\t", fset.File(node.Pos()).Name()) ast.Inspect(node, func(n ast.Node) bool { if typeSpecNode, ok := n.(*ast.TypeSpec); ok { if _, ok := typeSpecNode.Type.(*ast.InterfaceType); ok { fmt.Println("\t\t\tInterface:", pkg.TypesInfo.Defs[typeSpecNode.Name].Type().String()) interaceTable[pkg.TypesInfo.Defs[typeSpecNode.Name].Type().String()] = true } } return true }) } } return interaceTable } // InferRootFunctionsFromGraph tries to infer entry points from passed call graph. func InferRootFunctionsFromGraph(callgraph map[FuncDescriptor][]FuncDescriptor) []FuncDescriptor { var allFunctions map[FuncDescriptor]bool var rootFunctions []FuncDescriptor allFunctions = make(map[FuncDescriptor]bool) for k, v := range callgraph { allFunctions[k] = true for _, childFun := range v { allFunctions[childFun] = true } } for k := range allFunctions { _, exists := callgraph[k] if !exists { rootFunctions = append(rootFunctions, k) } } return rootFunctions } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/context_propagation.go000066400000000000000000000135601443314701600306450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "fmt" "go/ast" "golang.org/x/tools/go/packages" ) func isFunPartOfCallGraph(fun FuncDescriptor, callgraph map[FuncDescriptor][]FuncDescriptor) bool { // TODO this is not optimap o(n) for k, v := range callgraph { if k.TypeHash() == fun.TypeHash() { return true } for _, e := range v { if fun.TypeHash() == e.TypeHash() { return true } } } return false } // ContextPropagationPass. type ContextPropagationPass struct { } // Execute. func (pass *ContextPropagationPass) Execute( node *ast.File, analysis *PackageAnalysis, pkg *packages.Package, pkgs []*packages.Package) []Import { var imports []Import addImports := false // below variable is used // when callexpr is inside var decl // instead of functiondecl currentFun := FuncDescriptor{} emitEmptyContext := func(callExpr *ast.CallExpr, fun FuncDescriptor, ctxArg *ast.Ident) { addImports = true if currentFun != (FuncDescriptor{}) { visited := map[FuncDescriptor]bool{} if isPath(analysis.Callgraph, currentFun, analysis.RootFunctions[0], visited) { callExpr.Args = append([]ast.Expr{ctxArg}, callExpr.Args...) } else { contextTodo := &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_context", }, Sel: &ast.Ident{ Name: "TODO", }, }, Lparen: 62, Ellipsis: 0, } callExpr.Args = append([]ast.Expr{contextTodo}, callExpr.Args...) } return } contextTodo := &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_context", }, Sel: &ast.Ident{ Name: "TODO", }, }, Lparen: 62, Ellipsis: 0, } callExpr.Args = append([]ast.Expr{contextTodo}, callExpr.Args...) } emitCallExpr := func(ident *ast.Ident, n ast.Node, ctxArg *ast.Ident, pkgPath string) { if callExpr, ok := n.(*ast.CallExpr); ok { funId := pkgPath + "." + pkg.TypesInfo.Uses[ident].Name() fun := FuncDescriptor{ Id: funId, DeclType: pkg.TypesInfo.Uses[ident].Type().String(), CustomInjection: false} found := analysis.FuncDecls[fun] // inject context parameter only // to these functions for which function decl // exists if found { visited := map[FuncDescriptor]bool{} if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { fmt.Println("\t\t\tContextPropagation FuncCall:", funId, pkg.TypesInfo.Uses[ident].Type().String()) emitEmptyContext(callExpr, fun, ctxArg) } } } } ast.Inspect(node, func(n ast.Node) bool { ctxArg := &ast.Ident{ Name: "__atel_child_tracing_ctx", } ctxField := &ast.Field{ Names: []*ast.Ident{ { Name: "__atel_tracing_ctx", }, }, Type: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_context", }, Sel: &ast.Ident{ Name: "Context", }, }, } switch xNode := n.(type) { case *ast.FuncDecl: pkgPath := GetPkgPathForFunction(pkg, pkgs, xNode, analysis.Interfaces) funId := pkgPath + "." + pkg.TypesInfo.Defs[xNode.Name].Name() fun := FuncDescriptor{ Id: funId, DeclType: pkg.TypesInfo.Defs[xNode.Name].Type().String(), CustomInjection: false} currentFun = fun // inject context only // functions available in the call graph if !isFunPartOfCallGraph(fun, analysis.Callgraph) { break } if Contains(analysis.RootFunctions, fun) { break } visited := map[FuncDescriptor]bool{} if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { fmt.Println("\t\t\tContextPropagation FuncDecl:", funId, pkg.TypesInfo.Defs[xNode.Name].Type().String()) addImports = true xNode.Type.Params.List = append([]*ast.Field{ctxField}, xNode.Type.Params.List...) } case *ast.CallExpr: if ident, ok := xNode.Fun.(*ast.Ident); ok { if pkg.TypesInfo.Uses[ident] == nil { return false } pkgPath := GetPkgNameFromUsesTable(pkg, ident) emitCallExpr(ident, n, ctxArg, pkgPath) } if sel, ok := xNode.Fun.(*ast.SelectorExpr); ok { if pkg.TypesInfo.Uses[sel.Sel] == nil { return false } pkgPath := GetPkgNameFromUsesTable(pkg, sel.Sel) if sel.X != nil { pkgPath = GetSelectorPkgPath(sel, pkg, pkgPath) } emitCallExpr(sel.Sel, n, ctxArg, pkgPath) } case *ast.TypeSpec: iname := xNode.Name iface, ok := xNode.Type.(*ast.InterfaceType) if !ok { return true } for _, method := range iface.Methods.List { funcType, ok := method.Type.(*ast.FuncType) if !ok { return true } visited := map[FuncDescriptor]bool{} pkgPath := GetPkgNameFromDefsTable(pkg, method.Names[0]) funId := pkgPath + "." + iname.Name + "." + pkg.TypesInfo.Defs[method.Names[0]].Name() fun := FuncDescriptor{ Id: funId, DeclType: pkg.TypesInfo.Defs[method.Names[0]].Type().String(), CustomInjection: false} if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { fmt.Println("\t\t\tContext Propagation InterfaceType", fun.Id, fun.DeclType) addImports = true funcType.Params.List = append([]*ast.Field{ctxField}, funcType.Params.List...) } } } return true }) if addImports { imports = append(imports, Import{"__atel_context", "context", Add}) } return imports } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/instrumentation.go000066400000000000000000000174771443314701600300340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "fmt" "go/ast" "go/token" "golang.org/x/tools/go/packages" ) // InstrumentationPass. type InstrumentationPass struct { } func makeInitStmts(name string) []ast.Stmt { childTracingSupress := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "_", }, }, Tok: token.ASSIGN, Rhs: []ast.Expr{ &ast.Ident{ Name: "__atel_child_tracing_ctx", }, }, } s1 := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "__atel_ts", }, }, Tok: token.DEFINE, Rhs: []ast.Expr{ &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "rtlib", }, Sel: &ast.Ident{ Name: "NewTracingState", }, }, Lparen: 54, Ellipsis: 0, }, }, } s2 := &ast.DeferStmt{ Defer: 27, Call: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "rtlib", }, Sel: &ast.Ident{ Name: "Shutdown", }, }, Lparen: 48, Args: []ast.Expr{ &ast.Ident{ Name: "__atel_ts", }, }, Ellipsis: 0, }, } s3 := &ast.ExprStmt{ X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_otel", }, Sel: &ast.Ident{ Name: "SetTracerProvider", }, }, Lparen: 49, Args: []ast.Expr{ &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_ts", }, Sel: &ast.Ident{ Name: "Tp", }, }, }, Ellipsis: 0, }, } s4 := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "__atel_ctx", }, }, Tok: token.DEFINE, Rhs: []ast.Expr{ &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_context", }, Sel: &ast.Ident{ Name: "Background", }, }, Lparen: 52, Ellipsis: 0, }, }, } s5 := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "__atel_child_tracing_ctx", }, &ast.Ident{ Name: "__atel_span", }, }, Tok: token.DEFINE, Rhs: []ast.Expr{ &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_otel", }, Sel: &ast.Ident{ Name: "Tracer", }, }, Lparen: 50, Args: []ast.Expr{ &ast.Ident{ Name: `"` + name + `"`, }, }, Ellipsis: 0, }, Sel: &ast.Ident{ Name: "Start", }, }, Lparen: 62, Args: []ast.Expr{ &ast.Ident{ Name: "__atel_ctx", }, &ast.Ident{ Name: `"` + name + `"`, }, }, Ellipsis: 0, }, }, } s6 := &ast.DeferStmt{ Defer: 27, Call: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_span", }, Sel: &ast.Ident{ Name: "End", }, }, Lparen: 41, Ellipsis: 0, }, } stmts := []ast.Stmt{s1, s2, s3, s4, s5, childTracingSupress, s6} return stmts } func makeSpanStmts(name string, paramName string) []ast.Stmt { s1 := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "__atel_child_tracing_ctx", }, &ast.Ident{ Name: "__atel_span", }, }, Tok: token.DEFINE, Rhs: []ast.Expr{ &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_otel", }, Sel: &ast.Ident{ Name: "Tracer", }, }, Lparen: 50, Args: []ast.Expr{ &ast.Ident{ Name: `"` + name + `"`, }, }, Ellipsis: 0, }, Sel: &ast.Ident{ Name: "Start", }, }, Lparen: 62, Args: []ast.Expr{ &ast.Ident{ Name: paramName, }, &ast.Ident{ Name: `"` + name + `"`, }, }, Ellipsis: 0, }, }, } s2 := &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.Ident{ Name: "_", }, }, Tok: token.ASSIGN, Rhs: []ast.Expr{ &ast.Ident{ Name: "__atel_child_tracing_ctx", }, }, } s3 := &ast.DeferStmt{ Defer: 27, Call: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: &ast.Ident{ Name: "__atel_span", }, Sel: &ast.Ident{ Name: "End", }, }, Lparen: 41, Ellipsis: 0, }, } stmts := []ast.Stmt{s1, s2, s3} return stmts } // Execute. func (pass *InstrumentationPass) Execute( node *ast.File, analysis *PackageAnalysis, pkg *packages.Package, pkgs []*packages.Package) []Import { var imports []Import addImports := false addContext := false // store all function literals positions // that are part of assignment statement // it's used to avoid injection into literal // more than once var functionLiteralPositions []token.Pos ast.Inspect(node, func(n ast.Node) bool { switch x := n.(type) { case *ast.FuncDecl: pkgPath := GetPkgPathForFunction(pkg, pkgs, x, analysis.Interfaces) fundId := pkgPath + "." + pkg.TypesInfo.Defs[x.Name].Name() fun := FuncDescriptor{ Id: fundId, DeclType: pkg.TypesInfo.Defs[x.Name].Type().String(), CustomInjection: false} // check if it's root function or // one of function in call graph // and emit proper ast nodes _, exists := analysis.Callgraph[fun] if !exists { if !Contains(analysis.RootFunctions, fun) { return false } } for _, root := range analysis.RootFunctions { visited := map[FuncDescriptor]bool{} fmt.Println("\t\t\tInstrumentation FuncDecl:", fundId, pkg.TypesInfo.Defs[x.Name].Type().String()) if isPath(analysis.Callgraph, fun, root, visited) && fun.TypeHash() != root.TypeHash() { x.Body.List = append(makeSpanStmts(x.Name.Name, "__atel_tracing_ctx"), x.Body.List...) addContext = true addImports = true } else { // check whether this function is root function if !Contains(analysis.RootFunctions, fun) { return false } x.Body.List = append(makeInitStmts(x.Name.Name), x.Body.List...) addContext = true addImports = true } } case *ast.AssignStmt: for _, e := range x.Lhs { if ident, ok := e.(*ast.Ident); ok { _ = ident pkgPath := "" pkgPath = GetPkgNameFromDefsTable(pkg, ident) if pkg.TypesInfo.Defs[ident] == nil { return false } fundId := pkgPath + "." + pkg.TypesInfo.Defs[ident].Name() fun := FuncDescriptor{ Id: fundId, DeclType: pkg.TypesInfo.Defs[ident].Type().String(), CustomInjection: true} _, exists := analysis.Callgraph[fun] if exists { return false } } } for _, e := range x.Rhs { if funLit, ok := e.(*ast.FuncLit); ok { functionLiteralPositions = append(functionLiteralPositions, funLit.Pos()) funLit.Body.List = append(makeSpanStmts("anonymous", "__atel_child_tracing_ctx"), funLit.Body.List...) addImports = true addContext = true } } case *ast.FuncLit: for _, pos := range functionLiteralPositions { if pos == x.Pos() { return false } } x.Body.List = append(makeSpanStmts("anonymous", "__atel_child_tracing_ctx"), x.Body.List...) addImports = true addContext = true } return true }) if addContext { imports = append(imports, Import{"__atel_context", "context", Add}) } if addImports { imports = append(imports, Import{"__atel_otel", "go.opentelemetry.io/otel", Add}) } return imports } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/otel_pruning.go000066400000000000000000000106571443314701600272670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "go/ast" "strings" "golang.org/x/tools/go/packages" ) func removeStmt(slice []ast.Stmt, s int) []ast.Stmt { return append(slice[:s], slice[s+1:]...) } func removeField(slice []*ast.Field, s int) []*ast.Field { return append(slice[:s], slice[s+1:]...) } func removeExpr(slice []ast.Expr, s int) []ast.Expr { return append(slice[:s], slice[s+1:]...) } // OtelPruner. type OtelPruner struct { } func inspectFuncContent(fType *ast.FuncType, fBody *ast.BlockStmt) { for index := 0; index < len(fType.Params.List); index++ { param := fType.Params.List[index] for _, ident := range param.Names { if strings.Contains(ident.Name, "__atel_") { fType.Params.List = removeField(fType.Params.List, index) index-- } } } for index := 0; index < len(fBody.List); index++ { stmt := fBody.List[index] switch bodyStmt := stmt.(type) { case *ast.AssignStmt: if ident, ok := bodyStmt.Lhs[0].(*ast.Ident); ok { if strings.Contains(ident.Name, "__atel_") { fBody.List = removeStmt(fBody.List, index) index-- } } if ident, ok := bodyStmt.Rhs[0].(*ast.Ident); ok { if strings.Contains(ident.Name, "__atel_") { fBody.List = removeStmt(fBody.List, index) index-- } } case *ast.ExprStmt: if call, ok := bodyStmt.X.(*ast.CallExpr); ok { if sel, ok := call.Fun.(*ast.SelectorExpr); ok { if strings.Contains(sel.Sel.Name, "SetTracerProvider") { fBody.List = removeStmt(fBody.List, index) index-- } } } case *ast.DeferStmt: if sel, ok := bodyStmt.Call.Fun.(*ast.SelectorExpr); ok { if strings.Contains(sel.Sel.Name, "Shutdown") { if ident, ok := sel.X.(*ast.Ident); ok { if strings.Contains(ident.Name, "rtlib") { fBody.List = removeStmt(fBody.List, index) index-- } } } if ident, ok := sel.X.(*ast.Ident); ok { if strings.Contains(ident.Name, "__atel_") { fBody.List = removeStmt(fBody.List, index) index-- } } } } } } // Execute. func (pass *OtelPruner) Execute( node *ast.File, analysis *PackageAnalysis, pkg *packages.Package, pkgs []*packages.Package) []Import { var imports []Import ast.Inspect(node, func(n ast.Node) bool { switch x := n.(type) { case *ast.FuncDecl: inspectFuncContent(x.Type, x.Body) case *ast.CallExpr: for argIndex := 0; argIndex < len(x.Args); argIndex++ { if ident, ok := x.Args[argIndex].(*ast.Ident); ok { if strings.Contains(ident.Name, "__atel_") { x.Args = removeExpr(x.Args, argIndex) argIndex-- } } } for argIndex := 0; argIndex < len(x.Args); argIndex++ { if c, ok := x.Args[argIndex].(*ast.CallExpr); ok { if sel, ok := c.Fun.(*ast.SelectorExpr); ok { if ident, ok := sel.X.(*ast.Ident); ok { if strings.Contains(ident.Name, "__atel_") { x.Args = removeExpr(x.Args, argIndex) argIndex-- } } } } } case *ast.FuncLit: inspectFuncContent(x.Type, x.Body) case *ast.TypeSpec: iface, ok := x.Type.(*ast.InterfaceType) if !ok { return true } for _, method := range iface.Methods.List { funcType, ok := method.Type.(*ast.FuncType) if !ok { continue } for argIndex := 0; argIndex < len(funcType.Params.List); argIndex++ { for _, ident := range funcType.Params.List[argIndex].Names { if strings.Contains(ident.Name, "__atel_") { funcType.Params.List = removeField(funcType.Params.List, argIndex) argIndex-- } } } } } return true }) imports = append(imports, Import{"__atel_context", "context", Remove}) imports = append(imports, Import{"__atel_otel", "go.opentelemetry.io/otel", Remove}) imports = append(imports, Import{"__atel_otelhttp", "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", Remove}) return imports } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/lib/tools.go000066400000000000000000000031211443314701600257060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package lib // import "go.opentelemetry.io/contrib/instrgen/lib" import ( "os" "path/filepath" ) // SearchFiles. func SearchFiles(root string, ext string) []string { var files []string err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if filepath.Ext(path) == ext { files = append(files, path) } return nil }) if err != nil { panic(err) } return files } func isPath( callGraph map[FuncDescriptor][]FuncDescriptor, current FuncDescriptor, goal FuncDescriptor, visited map[FuncDescriptor]bool) bool { if current == goal { return true } value, ok := callGraph[current] if ok { for _, child := range value { exists := visited[child] if exists { continue } visited[child] = true if isPath(callGraph, child, goal, visited) { return true } } } return false } // Contains. func Contains(a []FuncDescriptor, x FuncDescriptor) bool { for _, n := range a { if x.TypeHash() == n.TypeHash() { return true } } return false } open-telemetry-opentelemetry-go-contrib-2135499/instrgen/rtlib/000077500000000000000000000000001443314701600245705ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrgen/rtlib/rtlib.go000066400000000000000000000044141443314701600262360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Basic runtime library package rtlib // import "go.opentelemetry.io/contrib/instrgen/rtlib" import ( "context" "io" "log" "os" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/sdk/resource" trace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) // TracingState type. type TracingState struct { Logger *log.Logger File *os.File Tp *trace.TracerProvider } // NewTracingState. func NewTracingState() TracingState { var tracingState TracingState tracingState.Logger = log.New(os.Stdout, "", 0) // Write telemetry data to a file. var err error tracingState.File, err = os.Create("traces.txt") if err != nil { tracingState.Logger.Fatal(err) } var exp trace.SpanExporter exp, err = NewExporter(tracingState.File) if err != nil { tracingState.Logger.Fatal(err) } tracingState.Tp = trace.NewTracerProvider( trace.WithBatcher(exp), trace.WithResource(NewResource()), ) return tracingState } // NewExporter returns a console exporter. func NewExporter(w io.Writer) (trace.SpanExporter, error) { return stdouttrace.New( stdouttrace.WithWriter(w), // Use human readable output. stdouttrace.WithPrettyPrint(), // Do not print timestamps for the demo. stdouttrace.WithoutTimestamps(), ) } // NewResource returns a resource describing this application. func NewResource() *resource.Resource { r, _ := resource.Merge( resource.Default(), resource.NewWithAttributes( semconv.SchemaURL, ), ) return r } // Shutdown. func Shutdown(ts TracingState) { if err := ts.Tp.Shutdown(context.Background()); err != nil { ts.Logger.Fatal(err) } } // AutoEntryPoint. func AutotelEntryPoint() { } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/000077500000000000000000000000001443314701600250665ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/README.md000066400000000000000000000146501443314701600263530ustar00rootroot00000000000000# Instrumentation Code contained in this directory contains instrumentation for 3rd-party Go packages and some packages from the standard library. ## New Instrumentation **Do not submit pull requests for new instrumentation without reading the following.** This project is dedicated to promoting the development of quality instrumentation using OpenTelemetry. To achieve this goal, we recognize that the instrumentation needs to be written using the best practices of OpenTelemetry, but also by developers that understand the package they are instrumenting. Additionally, the produced instrumentation needs to be maintained and evolved. The size of the OpenTelemetry Go developer community is not large enough to support an ever growing amount of instrumentation. Therefore, to reach our goal, we have the following recommendations for where instrumentation packages should live. 1. Native to the instrumented package 2. A dedicated public repository 3. Here in the opentelemetry-go-contrib repository If possible, OpenTelemetry instrumentation should be included in the instrumented package. This will ensure the instrumentation reaches all package users, and is continuously maintained by developers that understand the package. If instrumentation cannot be directly included in the package it is instrumenting, it should be hosted in a dedicated public repository owned by its maintainer(s). This will appropriately assign maintenance responsibilities for the instrumentation and ensure these maintainers have the needed privilege to maintain the code. The last place instrumentation should be hosted is here in this repository. Maintaining instrumentation here hampers the development of OpenTelemetry for Go and therefore should be avoided. When instrumentation cannot be included in a target package and there is good reason to not host it in a separate and dedicated repository an [instrumentation request](https://github.com/open-telemetry/opentelemetry-go-contrib/issues/new/choose) should be filed. The instrumentation request needs to be accepted before any pull requests for the instrumentation can be considered for merging. Regardless of where instrumentation is hosted, it needs to be discoverable. The [OpenTelemetry registry](https://opentelemetry.io/registry/) exists to ensure that instrumentation is discoverable. You can find out how to add instrumentation to the registry [here](https://github.com/open-telemetry/opentelemetry.io#adding-a-project-to-the-opentelemetry-registry). ## Instrumentation Packages The [OpenTelemetry registry](https://opentelemetry.io/registry/) is the best place to discover instrumentation packages. It will include packages outside of this project. The following instrumentation packages are provided for popular Go packages and use-cases. | Instrumentation Package | Metrics | Traces | | :---------------------: | :-----: | :----: | | [github.com/astaxie/beego](./github.com/astaxie/beego/otelbeego) | ✓ | ✓ | | [github.com/aws/aws-sdk-go-v2](./github.com/aws/aws-sdk-go-v2/otelaws)| | ✓ | | [github.com/bradfitz/gomemcache](./github.com/bradfitz/gomemcache/memcache/otelmemcache) | | ✓ | | [github.com/emicklei/go-restful](./github.com/emicklei/go-restful/otelrestful) | | ✓ | | [github.com/gin-gonic/gin](./github.com/gin-gonic/gin/otelgin) | | ✓ | | [github.com/go-kit/kit](./github.com/go-kit/kit/otelkit) | | ✓ | | [github.com/gocql/gocql](./github.com/gocql/gocql/otelgocql) | ✓ | ✓ | | [github.com/gorilla/mux](./github.com/gorilla/mux/otelmux) | | ✓ | | [github.com/labstack/echo](./github.com/labstack/echo/otelecho) | | ✓ | | [github.com/Shopify/sarama](./github.com/Shopify/sarama/otelsarama) | | ✓ | | [go.mongodb.org/mongo-driver](./go.mongodb.org/mongo-driver/mongo/otelmongo) | | ✓ | | [google.golang.org/grpc](./google.golang.org/grpc/otelgrpc) | ✓ | ✓ | | [gopkg.in/macaron.v1](./gopkg.in/macaron.v1/otelmacaron) | | ✓ | | [host](./host) | ✓ | | | [net/http](./net/http/otelhttp) | ✓ | ✓ | | [net/http/httptrace](./net/http/httptrace/otelhttptrace) | | ✓ | | [runtime](./runtime) | ✓ | | ## Organization In order to ensure the maintainability and discoverability of instrumentation packages, the following guidelines MUST be followed. ### Packaging All instrumentation packages SHOULD be of the form: ``` go.opentelemetry.io/contrib/instrumentation/{IMPORT_PATH}/otel{PACKAGE_NAME} ``` Where the [`{IMPORT_PATH}`](https://golang.org/ref/spec#ImportPath) and [`{PACKAGE_NAME}`](https://golang.org/ref/spec#PackageName) are the standard Go identifiers for the package being instrumented. For example: - `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` - `go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron` - `go.opentelemetry.io/contrib/instrumentation/database/sql/otelsql` Exceptions to this rule exist. For example, the [runtime](./runtime) and [host](./host) instrumentation do not instrument any Go package and therefore do not fit this structure. ### Contents All instrumentation packages MUST adhere to [the projects' contributing guidelines](../CONTRIBUTING.md). Additionally the following guidelines for package composition need to be followed. - All instrumentation packages MUST be a Go module. Therefore, an appropriately configured `go.mod` and `go.sum` need to exist for each package. - To help understand the instrumentation a Go package documentation SHOULD be included. This documentation SHOULD be in a dedicated `doc.go` file if the package is more than one file. It SHOULD contain useful information like what the purpose of the instrumentation is, how to use it, and any compatibility restrictions that might exist. - Examples of how to actually use the instrumentation SHOULD be included. - All instrumentation packages MUST provide an option to accept a `TracerProvider` if it uses a Tracer, a `MeterProvider` if it uses a Meter, and `Propagators` if it handles any context propagation. Also, packages MUST use the default `TracerProvider`, `MeterProvider`, and `Propagators` supplied by the `global` package if no optional one is provided. - All instrumentation packages MUST NOT provide an option to accept a `Tracer` or `Meter`. - All instrumentation packages MUST create any used `Tracer` or `Meter` with a name matching the instrumentation package name. - All instrumentation packages MUST create any used `Tracer` or `Meter` with a semantic version corresponding to the version of the module containing the instrumentation. open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/000077500000000000000000000000001443314701600271255ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/000077500000000000000000000000001443314701600305465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/000077500000000000000000000000001443314701600320125ustar00rootroot00000000000000otelsarama/000077500000000000000000000000001443314701600340635ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/saramaconsumer.go000066400000000000000000000041471443314701600362530ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "github.com/Shopify/sarama" ) type partitionConsumer struct { sarama.PartitionConsumer dispatcher consumerMessagesDispatcher } // Messages returns the read channel for the messages that are returned by // the broker. func (pc *partitionConsumer) Messages() <-chan *sarama.ConsumerMessage { return pc.dispatcher.Messages() } // WrapPartitionConsumer wraps a sarama.PartitionConsumer causing each received // message to be traced. func WrapPartitionConsumer(pc sarama.PartitionConsumer, opts ...Option) sarama.PartitionConsumer { cfg := newConfig(opts...) dispatcher := newConsumerMessagesDispatcherWrapper(pc, cfg) go dispatcher.Run() wrapped := &partitionConsumer{ PartitionConsumer: pc, dispatcher: dispatcher, } return wrapped } type consumer struct { sarama.Consumer opts []Option } // ConsumePartition invokes Consumer.ConsumePartition and wraps the resulting // PartitionConsumer. func (c *consumer) ConsumePartition(topic string, partition int32, offset int64) (sarama.PartitionConsumer, error) { pc, err := c.Consumer.ConsumePartition(topic, partition, offset) if err != nil { return nil, err } return WrapPartitionConsumer(pc, c.opts...), nil } // WrapConsumer wraps a sarama.Consumer wrapping any PartitionConsumer created // via Consumer.ConsumePartition. func WrapConsumer(c sarama.Consumer, opts ...Option) sarama.Consumer { return &consumer{ Consumer: c, opts: opts, } } consumer_group.go000066400000000000000000000035571443314701600374730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "github.com/Shopify/sarama" ) type consumerGroupHandler struct { sarama.ConsumerGroupHandler cfg config } // ConsumeClaim wraps the session and claim to add instruments for messages. // It implements parts of `ConsumerGroupHandler`. func (h *consumerGroupHandler) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { // Wrap claim dispatcher := newConsumerMessagesDispatcherWrapper(claim, h.cfg) go dispatcher.Run() claim = &consumerGroupClaim{ ConsumerGroupClaim: claim, dispatcher: dispatcher, } return h.ConsumerGroupHandler.ConsumeClaim(session, claim) } // WrapConsumerGroupHandler wraps a sarama.ConsumerGroupHandler causing each received // message to be traced. func WrapConsumerGroupHandler(handler sarama.ConsumerGroupHandler, opts ...Option) sarama.ConsumerGroupHandler { cfg := newConfig(opts...) return &consumerGroupHandler{ ConsumerGroupHandler: handler, cfg: cfg, } } type consumerGroupClaim struct { sarama.ConsumerGroupClaim dispatcher consumerMessagesDispatcher } func (c *consumerGroupClaim) Messages() <-chan *sarama.ConsumerMessage { return c.dispatcher.Messages() } consumer_group_test.go000066400000000000000000000014521443314701600405220ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // TODO: add test for consumer group // Currently, sarama does not have a mock consumer group, so it's hard to // write a unit test. // Related PR: https://github.com/Shopify/sarama/pull/1750 consumer_test.go000066400000000000000000000047351443314701600373150ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama import ( "testing" "github.com/Shopify/sarama" "github.com/Shopify/sarama/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" ) const ( topic = "test-topic" ) func TestConsumerConsumePartitionWithError(t *testing.T) { // Mock partition consumer controller mockConsumer := mocks.NewConsumer(t, sarama.NewConfig()) mockConsumer.ExpectConsumePartition(topic, 0, 0) consumer := WrapConsumer(mockConsumer) _, err := consumer.ConsumePartition(topic, 0, 0) assert.NoError(t, err) // Consume twice _, err = consumer.ConsumePartition(topic, 0, 0) assert.Error(t, err) } func BenchmarkWrapPartitionConsumer(b *testing.B) { // Mock provider provider := trace.NewNoopTracerProvider() mockPartitionConsumer, partitionConsumer := createMockPartitionConsumer(b) partitionConsumer = WrapPartitionConsumer(partitionConsumer, WithTracerProvider(provider)) message := sarama.ConsumerMessage{Key: []byte("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockPartitionConsumer.YieldMessage(&message) <-partitionConsumer.Messages() } } func BenchmarkMockPartitionConsumer(b *testing.B) { mockPartitionConsumer, partitionConsumer := createMockPartitionConsumer(b) message := sarama.ConsumerMessage{Key: []byte("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockPartitionConsumer.YieldMessage(&message) <-partitionConsumer.Messages() } } func createMockPartitionConsumer(b *testing.B) (*mocks.PartitionConsumer, sarama.PartitionConsumer) { // Mock partition consumer controller consumer := mocks.NewConsumer(b, sarama.NewConfig()) mockPartitionConsumer := consumer.ExpectConsumePartition(topic, 0, 0) // Create partition consumer partitionConsumer, err := consumer.ConsumePartition(topic, 0, 0) require.NoError(b, err) return mockPartitionConsumer, partitionConsumer } dispatcher.go000066400000000000000000000051351443314701600365440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "context" "fmt" "strconv" "github.com/Shopify/sarama" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) type consumerMessagesDispatcher interface { Messages() <-chan *sarama.ConsumerMessage } type consumerMessagesDispatcherWrapper struct { d consumerMessagesDispatcher messages chan *sarama.ConsumerMessage cfg config } func newConsumerMessagesDispatcherWrapper(d consumerMessagesDispatcher, cfg config) *consumerMessagesDispatcherWrapper { return &consumerMessagesDispatcherWrapper{ d: d, messages: make(chan *sarama.ConsumerMessage), cfg: cfg, } } // Messages returns the read channel for the messages that are returned by // the broker. func (w *consumerMessagesDispatcherWrapper) Messages() <-chan *sarama.ConsumerMessage { return w.messages } func (w *consumerMessagesDispatcherWrapper) Run() { msgs := w.d.Messages() for msg := range msgs { // Extract a span context from message to link. carrier := NewConsumerMessageCarrier(msg) parentSpanContext := w.cfg.Propagators.Extract(context.Background(), carrier) // Create a span. attrs := []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(msg.Topic), semconv.MessagingOperationReceive, semconv.MessagingMessageID(strconv.FormatInt(msg.Offset, 10)), semconv.MessagingKafkaSourcePartition(int(msg.Partition)), } opts := []trace.SpanStartOption{ trace.WithAttributes(attrs...), trace.WithSpanKind(trace.SpanKindConsumer), } newCtx, span := w.cfg.Tracer.Start(parentSpanContext, fmt.Sprintf("%s receive", msg.Topic), opts...) // Inject current span context, so consumers can use it to propagate span. w.cfg.Propagators.Inject(newCtx, carrier) // Send messages back to user. w.messages <- msg span.End() } close(w.messages) } doc.go000066400000000000000000000021441443314701600351600ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelsarama instruments the github.com/Shopify/sarama package. // // The consumer's span will be created as a child of the producer's span. // // Context propagation only works on Kafka versions higher than 0.11.0.0 which supports record headers. // (https://archive.apache.org/dist/kafka/0.11.0.0/RELEASE_NOTES.html) // // Based on: https://github.com/DataDog/dd-trace-go/tree/v1/contrib/Shopify/sarama package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" example/000077500000000000000000000000001443314701600355165ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsaramaREADME.md000066400000000000000000000012001443314701600367660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example# Kafka Sarama instrumentation example A Kafka producer and consumer using Sarama with instrumentation. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `Kafka` and `ZooKeeper` services to run the example: ```sh docker-compose up -d zoo kafka ``` Then up the `kafka-producer` service to produce a message into Kafka: ```sh docker-compose up kafka-producer ``` At last, up the `kafka-consumer` service to consume messages from Kafka: ```sh docker-compose up kafka-consumer ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` consumer/000077500000000000000000000000001443314701600373515ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/exampleDockerfile000066400000000000000000000014271443314701600413470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example/consumer# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/Shopify/sarama/otelsarama/example FROM base AS kafka-consumer RUN go install ./consumer/consumer.go CMD ["/go/bin/consumer"] consumer.go000066400000000000000000000073601443314701600415410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example/consumer// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "flag" "fmt" "log" "os" "os/signal" "strings" "time" "github.com/Shopify/sarama" "go.opentelemetry.io/otel" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example" ) var ( brokers = flag.String("brokers", os.Getenv("KAFKA_PEERS"), "The Kafka brokers to connect to, as a comma separated list") ) func main() { tp, err := example.InitTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() flag.Parse() if *brokers == "" { flag.PrintDefaults() os.Exit(1) } brokerList := strings.Split(*brokers, ",") log.Printf("Kafka brokers: %s", strings.Join(brokerList, ", ")) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() if err := startConsumerGroup(ctx, brokerList); err != nil { log.Fatal(err) } <-ctx.Done() } func startConsumerGroup(ctx context.Context, brokerList []string) error { consumerGroupHandler := Consumer{} // Wrap instrumentation handler := otelsarama.WrapConsumerGroupHandler(&consumerGroupHandler) config := sarama.NewConfig() config.Version = sarama.V2_5_0_0 config.Consumer.Offsets.Initial = sarama.OffsetOldest // Create consumer group consumerGroup, err := sarama.NewConsumerGroup(brokerList, "example", config) if err != nil { return fmt.Errorf("starting consumer group: %w", err) } err = consumerGroup.Consume(ctx, []string{example.KafkaTopic}, handler) if err != nil { return fmt.Errorf("consuming via handler: %w", err) } return nil } func printMessage(msg *sarama.ConsumerMessage) { // Extract tracing info from message ctx := otel.GetTextMapPropagator().Extract(context.Background(), otelsarama.NewConsumerMessageCarrier(msg)) tr := otel.Tracer("consumer") _, span := tr.Start(ctx, "consume message", trace.WithAttributes( semconv.MessagingOperationProcess, )) defer span.End() // Emulate Work loads time.Sleep(1 * time.Second) log.Println("Successful to read message: ", string(msg.Value)) } // Consumer represents a Sarama consumer group consumer. type Consumer struct { } // Setup is run at the beginning of a new session, before ConsumeClaim. func (consumer *Consumer) Setup(sarama.ConsumerGroupSession) error { return nil } // Cleanup is run at the end of a session, once all ConsumeClaim goroutines have exited. func (consumer *Consumer) Cleanup(sarama.ConsumerGroupSession) error { return nil } // ConsumeClaim must start a consumer loop of ConsumerGroupClaim's Messages(). func (consumer *Consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { // NOTE: // Do not move the code below to a goroutine. // The `ConsumeClaim` itself is called within a goroutine, see: // https://github.com/Shopify/sarama/blob/master/consumer_group.go#L27-L29 for message := range claim.Messages() { printMessage(message) session.MarkMessage(message, "") } return nil } docker-compose.yml000066400000000000000000000041601443314701600411540ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: zoo: image: zookeeper:3.4.9 hostname: zoo ports: - "2181:2181" environment: ZOO_MY_ID: 1 ZOO_PORT: 2181 ZOO_SERVERS: server.1=zoo:2888:3888 networks: - example kafka: # Kafka version 2.5.0 image: confluentinc/cp-kafka:5.5.0 hostname: kafka ports: - "9092:9092" environment: KAFKA_ADVERTISED_LISTENERS: LISTENER_DOCKER_INTERNAL://kafka:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: LISTENER_DOCKER_INTERNAL:PLAINTEXT,LISTENER_DOCKER_EXTERNAL:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: LISTENER_DOCKER_INTERNAL KAFKA_ZOOKEEPER_CONNECT: "zoo:2181" KAFKA_BROKER_ID: 1 KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 depends_on: - zoo networks: - example kafka-producer: build: dockerfile: $PWD/producer/Dockerfile context: ../../../../../.. command: - "/bin/sh" - "-c" - "/go/bin/producer" environment: KAFKA_PEERS: kafka:19092 depends_on: - kafka networks: - example kafka-consumer: build: dockerfile: $PWD/consumer/Dockerfile context: ../../../../../.. command: - "/bin/sh" - "-c" - "/go/bin/consumer" environment: KAFKA_PEERS: kafka:19092 depends_on: - kafka networks: - example networks: example:go.mod000066400000000000000000000031501443314701600366230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama => ../ require ( github.com/Shopify/sarama v1.38.1 go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/eapache/go-resiliency v1.3.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.15.14 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000206221443314701600366530ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/examplegithub.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0= github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9ndfrgrXUbOGObLHKBR4Fl3nZXwM2c7OYTT8hM= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8= github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc= github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= init.go000066400000000000000000000026711443314701600370160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package example // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example" import ( "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) const ( // KafkaTopic name. KafkaTopic = "sarama-instrumentation-example" ) // InitTracer creates and registers globally a new TracerProvider. func InitTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{})) return tp, nil } producer/000077500000000000000000000000001443314701600373415ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/exampleDockerfile000066400000000000000000000014261443314701600413360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example/producer# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/Shopify/sarama/otelsarama/example FROM base AS kafka-producer RUN go install ./producer/producer.go CMD ["/go/bin/producer"] producer.go000066400000000000000000000057341443314701600415240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/example/producer// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "flag" "fmt" "log" "math/rand" "os" "strings" "time" "github.com/Shopify/sarama" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example" ) var ( brokers = flag.String("brokers", os.Getenv("KAFKA_PEERS"), "The Kafka brokers to connect to, as a comma separated list") ) func main() { tp, err := example.InitTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() flag.Parse() if *brokers == "" { flag.PrintDefaults() os.Exit(1) } brokerList := strings.Split(*brokers, ",") log.Printf("Kafka brokers: %s", strings.Join(brokerList, ", ")) producer, err := newAccessLogProducer(brokerList) if err != nil { log.Fatal(err) } // Create root span tr := otel.Tracer("producer") ctx, span := tr.Start(context.Background(), "produce message") defer span.End() // Inject tracing info into message rng := rand.New(rand.NewSource(time.Now().Unix())) msg := sarama.ProducerMessage{ Topic: example.KafkaTopic, Key: sarama.StringEncoder("random_number"), Value: sarama.StringEncoder(fmt.Sprintf("%d", rng.Intn(1000))), } otel.GetTextMapPropagator().Inject(ctx, otelsarama.NewProducerMessageCarrier(&msg)) producer.Input() <- &msg successMsg := <-producer.Successes() log.Println("Successful to write message, offset:", successMsg.Offset) err = producer.Close() if err != nil { span.SetStatus(codes.Error, err.Error()) log.Fatalln("Failed to close producer:", err) } } func newAccessLogProducer(brokerList []string) (sarama.AsyncProducer, error) { config := sarama.NewConfig() config.Version = sarama.V2_5_0_0 // So we can know the partition and offset of messages. config.Producer.Return.Successes = true producer, err := sarama.NewAsyncProducer(brokerList, config) if err != nil { return nil, fmt.Errorf("starting Sarama producer: %w", err) } // Wrap instrumentation producer = otelsarama.WrapAsyncProducer(config, producer) // We will log to STDOUT if we're not able to produce messages. go func() { for err := range producer.Errors() { log.Println("Failed to write message:", err) } }() return producer, nil } go.mod000066400000000000000000000027611443314701600351770ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsaramamodule go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama go 1.19 require ( github.com/Shopify/sarama v1.38.1 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/eapache/go-resiliency v1.3.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.15.14 // indirect github.com/kr/text v0.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000210261443314701600352170ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsaramagithub.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0= github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9ndfrgrXUbOGObLHKBR4Fl3nZXwM2c7OYTT8hM= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8= github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc= github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= message.go000066400000000000000000000064131443314701600360420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "github.com/Shopify/sarama" "go.opentelemetry.io/otel/propagation" ) var _ propagation.TextMapCarrier = (*ProducerMessageCarrier)(nil) var _ propagation.TextMapCarrier = (*ConsumerMessageCarrier)(nil) // ProducerMessageCarrier injects and extracts traces from a sarama.ProducerMessage. type ProducerMessageCarrier struct { msg *sarama.ProducerMessage } // NewProducerMessageCarrier creates a new ProducerMessageCarrier. func NewProducerMessageCarrier(msg *sarama.ProducerMessage) ProducerMessageCarrier { return ProducerMessageCarrier{msg: msg} } // Get retrieves a single value for a given key. func (c ProducerMessageCarrier) Get(key string) string { for _, h := range c.msg.Headers { if string(h.Key) == key { return string(h.Value) } } return "" } // Set sets a header. func (c ProducerMessageCarrier) Set(key, val string) { // Ensure uniqueness of keys for i := 0; i < len(c.msg.Headers); i++ { if string(c.msg.Headers[i].Key) == key { c.msg.Headers = append(c.msg.Headers[:i], c.msg.Headers[i+1:]...) i-- } } c.msg.Headers = append(c.msg.Headers, sarama.RecordHeader{ Key: []byte(key), Value: []byte(val), }) } // Keys returns a slice of all key identifiers in the carrier. func (c ProducerMessageCarrier) Keys() []string { out := make([]string, len(c.msg.Headers)) for i, h := range c.msg.Headers { out[i] = string(h.Key) } return out } // ConsumerMessageCarrier injects and extracts traces from a sarama.ConsumerMessage. type ConsumerMessageCarrier struct { msg *sarama.ConsumerMessage } // NewConsumerMessageCarrier creates a new ConsumerMessageCarrier. func NewConsumerMessageCarrier(msg *sarama.ConsumerMessage) ConsumerMessageCarrier { return ConsumerMessageCarrier{msg: msg} } // Get retrieves a single value for a given key. func (c ConsumerMessageCarrier) Get(key string) string { for _, h := range c.msg.Headers { if h != nil && string(h.Key) == key { return string(h.Value) } } return "" } // Set sets a header. func (c ConsumerMessageCarrier) Set(key, val string) { // Ensure uniqueness of keys for i := 0; i < len(c.msg.Headers); i++ { if c.msg.Headers[i] != nil && string(c.msg.Headers[i].Key) == key { c.msg.Headers = append(c.msg.Headers[:i], c.msg.Headers[i+1:]...) i-- } } c.msg.Headers = append(c.msg.Headers, &sarama.RecordHeader{ Key: []byte(key), Value: []byte(val), }) } // Keys returns a slice of all key identifiers in the carrier. func (c ConsumerMessageCarrier) Keys() []string { out := make([]string, len(c.msg.Headers)) for i, h := range c.msg.Headers { out[i] = string(h.Key) } return out } message_test.go000066400000000000000000000120051443314701600370730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama import ( "testing" "github.com/Shopify/sarama" "github.com/stretchr/testify/assert" ) func TestProducerMessageCarrierGet(t *testing.T) { testCases := []struct { name string carrier ProducerMessageCarrier key string expected string }{ { name: "exists", carrier: ProducerMessageCarrier{msg: &sarama.ProducerMessage{Headers: []sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }}}, key: "foo", expected: "bar", }, { name: "not exists", carrier: ProducerMessageCarrier{msg: &sarama.ProducerMessage{Headers: []sarama.RecordHeader{}}}, key: "foo", expected: "", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := tc.carrier.Get(tc.key) assert.Equal(t, tc.expected, result) }) } } func TestProducerMessageCarrierSet(t *testing.T) { msg := sarama.ProducerMessage{Headers: []sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }} carrier := ProducerMessageCarrier{msg: &msg} carrier.Set("foo", "bar2") carrier.Set("foo2", "bar2") carrier.Set("foo2", "bar3") carrier.Set("foo3", "bar4") assert.ElementsMatch(t, carrier.msg.Headers, []sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar2")}, {Key: []byte("foo2"), Value: []byte("bar3")}, {Key: []byte("foo3"), Value: []byte("bar4")}, }) } func TestProducerMessageCarrierKeys(t *testing.T) { testCases := []struct { name string carrier ProducerMessageCarrier expected []string }{ { name: "one", carrier: ProducerMessageCarrier{msg: &sarama.ProducerMessage{Headers: []sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }}}, expected: []string{"foo"}, }, { name: "none", carrier: ProducerMessageCarrier{msg: &sarama.ProducerMessage{Headers: []sarama.RecordHeader{}}}, expected: []string{}, }, { name: "many", carrier: ProducerMessageCarrier{msg: &sarama.ProducerMessage{Headers: []sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, {Key: []byte("baz"), Value: []byte("quux")}, }}}, expected: []string{"foo", "baz"}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := tc.carrier.Keys() assert.Equal(t, tc.expected, result) }) } } func TestConsumerMessageCarrierGet(t *testing.T) { testCases := []struct { name string carrier ConsumerMessageCarrier key string expected string }{ { name: "exists", carrier: ConsumerMessageCarrier{msg: &sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }}}, key: "foo", expected: "bar", }, { name: "not exists", carrier: ConsumerMessageCarrier{msg: &sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{}}}, key: "foo", expected: "", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := tc.carrier.Get(tc.key) assert.Equal(t, tc.expected, result) }) } } func TestConsumerMessageCarrierSet(t *testing.T) { msg := sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }} carrier := ConsumerMessageCarrier{msg: &msg} carrier.Set("foo", "bar2") carrier.Set("foo2", "bar2") carrier.Set("foo2", "bar3") carrier.Set("foo3", "bar4") assert.ElementsMatch(t, carrier.msg.Headers, []*sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar2")}, {Key: []byte("foo2"), Value: []byte("bar3")}, {Key: []byte("foo3"), Value: []byte("bar4")}, }) } func TestConsumerMessageCarrierKeys(t *testing.T) { testCases := []struct { name string carrier ConsumerMessageCarrier expected []string }{ { name: "one", carrier: ConsumerMessageCarrier{msg: &sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, }}}, expected: []string{"foo"}, }, { name: "none", carrier: ConsumerMessageCarrier{msg: &sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{}}}, expected: []string{}, }, { name: "many", carrier: ConsumerMessageCarrier{msg: &sarama.ConsumerMessage{Headers: []*sarama.RecordHeader{ {Key: []byte("foo"), Value: []byte("bar")}, {Key: []byte("baz"), Value: []byte("quux")}, }}}, expected: []string{"foo", "baz"}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := tc.carrier.Keys() assert.Equal(t, tc.expected, result) }) } } option.go000066400000000000000000000043401443314701600357230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const defaultTracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" type config struct { TracerProvider trace.TracerProvider Propagators propagation.TextMapPropagator Tracer trace.Tracer } // newConfig returns a config with all Options set. func newConfig(opts ...Option) config { cfg := config{ Propagators: otel.GetTextMapPropagator(), TracerProvider: otel.GetTracerProvider(), } for _, opt := range opts { opt.apply(&cfg) } cfg.Tracer = cfg.TracerProvider.Tracer( defaultTracerName, trace.WithInstrumentationVersion(Version()), ) return cfg } // Option interface used for setting optional config properties. type Option interface { apply(*config) } type optionFunc func(*config) func (fn optionFunc) apply(c *config) { fn(c) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithPropagators specifies propagators to use for extracting // information from the HTTP requests. If none are specified, global // ones will be used. func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagators != nil { cfg.Propagators = propagators } }) } option_test.go000066400000000000000000000055621443314701600367710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama import ( "context" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) // We need a fake tracer provider to ensure the one passed in options is the one used afterwards. // In order to avoid adding the SDK as a dependency, we use this mock. type fakeTracerProvider struct{} func (fakeTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return fakeTracer{ name: name, } } type fakeTracer struct { name string } func (fakeTracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { return ctx, nil } func TestNewConfig(t *testing.T) { tp := fakeTracerProvider{} prop := propagation.NewCompositeTextMapPropagator() testCases := []struct { name string opts []Option expected config }{ { name: "with provider", opts: []Option{ WithTracerProvider(tp), }, expected: config{ TracerProvider: tp, Tracer: tp.Tracer(defaultTracerName, trace.WithInstrumentationVersion(Version())), Propagators: otel.GetTextMapPropagator(), }, }, { name: "with empty provider", opts: []Option{ WithTracerProvider(nil), }, expected: config{ TracerProvider: otel.GetTracerProvider(), Tracer: otel.GetTracerProvider().Tracer(defaultTracerName, trace.WithInstrumentationVersion(Version())), Propagators: otel.GetTextMapPropagator(), }, }, { name: "with propagators", opts: []Option{ WithPropagators(prop), }, expected: config{ TracerProvider: otel.GetTracerProvider(), Tracer: otel.GetTracerProvider().Tracer(defaultTracerName, trace.WithInstrumentationVersion(Version())), Propagators: prop, }, }, { name: "with empty propagators", opts: []Option{ WithPropagators(nil), }, expected: config{ TracerProvider: otel.GetTracerProvider(), Tracer: otel.GetTracerProvider().Tracer(defaultTracerName, trace.WithInstrumentationVersion(Version())), Propagators: otel.GetTextMapPropagator(), }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := newConfig(tc.opts...) assert.Equal(t, tc.expected, result) }) } } producer.go000066400000000000000000000221061443314701600362360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" import ( "context" "encoding/binary" "fmt" "strconv" "sync" "github.com/Shopify/sarama" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) type syncProducer struct { sarama.SyncProducer cfg config saramaConfig *sarama.Config } // SendMessage calls sarama.SyncProducer.SendMessage and traces the request. func (p *syncProducer) SendMessage(msg *sarama.ProducerMessage) (partition int32, offset int64, err error) { span := startProducerSpan(p.cfg, p.saramaConfig.Version, msg) partition, offset, err = p.SyncProducer.SendMessage(msg) finishProducerSpan(span, partition, offset, err) return partition, offset, err } // SendMessages calls sarama.SyncProducer.SendMessages and traces the requests. func (p *syncProducer) SendMessages(msgs []*sarama.ProducerMessage) error { // Although there's only one call made to the SyncProducer, the messages are // treated individually, so we create a span for each one spans := make([]trace.Span, len(msgs)) for i, msg := range msgs { spans[i] = startProducerSpan(p.cfg, p.saramaConfig.Version, msg) } err := p.SyncProducer.SendMessages(msgs) for i, span := range spans { finishProducerSpan(span, msgs[i].Partition, msgs[i].Offset, err) } return err } // WrapSyncProducer wraps a sarama.SyncProducer so that all produced messages // are traced. func WrapSyncProducer(saramaConfig *sarama.Config, producer sarama.SyncProducer, opts ...Option) sarama.SyncProducer { cfg := newConfig(opts...) if saramaConfig == nil { saramaConfig = sarama.NewConfig() } return &syncProducer{ SyncProducer: producer, cfg: cfg, saramaConfig: saramaConfig, } } type asyncProducer struct { sarama.AsyncProducer input chan *sarama.ProducerMessage successes chan *sarama.ProducerMessage errors chan *sarama.ProducerError closeErr chan error closeSig chan struct{} closeAsyncSig chan struct{} } // Input returns the input channel. func (p *asyncProducer) Input() chan<- *sarama.ProducerMessage { return p.input } // Successes returns the successes channel. func (p *asyncProducer) Successes() <-chan *sarama.ProducerMessage { return p.successes } // Errors returns the errors channel. func (p *asyncProducer) Errors() <-chan *sarama.ProducerError { return p.errors } // AsyncClose async close producer. func (p *asyncProducer) AsyncClose() { close(p.input) close(p.closeAsyncSig) } // Close shuts down the producer and waits for any buffered messages to be // flushed. // // Due to the implement of sarama, some messages may lose successes or errors status // while closing. func (p *asyncProducer) Close() error { close(p.input) close(p.closeSig) return <-p.closeErr } type producerMessageContext struct { span trace.Span metadataBackup interface{} } // WrapAsyncProducer wraps a sarama.AsyncProducer so that all produced messages // are traced. It requires the underlying sarama Config, so we can know whether // or not successes will be returned. // // If `Return.Successes` is false, there is no way to know partition and offset of // the message. func WrapAsyncProducer(saramaConfig *sarama.Config, p sarama.AsyncProducer, opts ...Option) sarama.AsyncProducer { cfg := newConfig(opts...) if saramaConfig == nil { saramaConfig = sarama.NewConfig() } wrapped := &asyncProducer{ AsyncProducer: p, input: make(chan *sarama.ProducerMessage), successes: make(chan *sarama.ProducerMessage), errors: make(chan *sarama.ProducerError), closeErr: make(chan error), closeSig: make(chan struct{}), closeAsyncSig: make(chan struct{}), } var ( mtx sync.Mutex producerMessageContexts = make(map[interface{}]producerMessageContext) ) // Spawn Input producer goroutine. go func() { for { select { case <-wrapped.closeSig: wrapped.closeErr <- p.Close() return case <-wrapped.closeAsyncSig: p.AsyncClose() return case msg, ok := <-wrapped.input: if !ok { continue // wait for closeAsyncSig } span := startProducerSpan(cfg, saramaConfig.Version, msg) // Create message context, backend message metadata mc := producerMessageContext{ metadataBackup: msg.Metadata, span: span, } // Remember metadata using span ID as a cache key msg.Metadata = span.SpanContext().SpanID() if saramaConfig.Producer.Return.Successes { mtx.Lock() producerMessageContexts[msg.Metadata] = mc mtx.Unlock() } else { // If returning successes isn't enabled, we just finish the // span right away because there's no way to know when it will // be done. mc.span.End() } p.Input() <- msg } } }() // Sarama will consume all the successes and errors by itself while closing, // so we need to end these spans ourselves. var cleanupWg sync.WaitGroup // Spawn Successes consumer goroutine. cleanupWg.Add(1) go func() { defer func() { close(wrapped.successes) cleanupWg.Done() }() for msg := range p.Successes() { key := msg.Metadata mtx.Lock() if mc, ok := producerMessageContexts[key]; ok { delete(producerMessageContexts, key) finishProducerSpan(mc.span, msg.Partition, msg.Offset, nil) msg.Metadata = mc.metadataBackup // Restore message metadata } mtx.Unlock() wrapped.successes <- msg } }() // Spawn Errors consumer goroutine. cleanupWg.Add(1) go func() { defer func() { close(wrapped.errors) cleanupWg.Done() }() for errMsg := range p.Errors() { key := errMsg.Msg.Metadata mtx.Lock() if mc, ok := producerMessageContexts[key]; ok { delete(producerMessageContexts, key) finishProducerSpan(mc.span, errMsg.Msg.Partition, errMsg.Msg.Offset, errMsg.Err) errMsg.Msg.Metadata = mc.metadataBackup // Restore message metadata } mtx.Unlock() wrapped.errors <- errMsg } }() // Spawn spans cleanup goroutine. go func() { // wait until both consumer goroutines are closed cleanupWg.Wait() // end all remaining spans mtx.Lock() for _, mc := range producerMessageContexts { mc.span.End() } mtx.Unlock() }() return wrapped } // msgPayloadSize returns the approximate estimate of message size in bytes. // // For kafka version <= 0.10, the message size is // ~ 4(crc32) + 8(timestamp) + 4(key len) + 4(value len) + 4(message len) + 1(attrs) + 1(magic). // // For kafka version >= 0.11, the message size with varint encoding is // ~ 5 * (crc32, key len, value len, message len, attrs) + timestamp + 1 byte (magic). // + header key + header value + header key len + header value len. func msgPayloadSize(msg *sarama.ProducerMessage, kafkaVersion sarama.KafkaVersion) int { maximumRecordOverhead := 5*binary.MaxVarintLen32 + binary.MaxVarintLen64 + 1 producerMessageOverhead := 26 version := 1 if kafkaVersion.IsAtLeast(sarama.V0_11_0_0) { version = 2 } size := producerMessageOverhead if version >= 2 { size = maximumRecordOverhead for _, h := range msg.Headers { size += len(h.Key) + len(h.Value) + 2*binary.MaxVarintLen32 } } if msg.Key != nil { size += msg.Key.Length() } if msg.Value != nil { size += msg.Value.Length() } return size } func startProducerSpan(cfg config, version sarama.KafkaVersion, msg *sarama.ProducerMessage) trace.Span { // If there's a span context in the message, use that as the parent context. carrier := NewProducerMessageCarrier(msg) ctx := cfg.Propagators.Extract(context.Background(), carrier) // Create a span. attrs := []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(msg.Topic), semconv.MessagingMessagePayloadSizeBytes(msgPayloadSize(msg, version)), semconv.MessagingOperationPublish, } opts := []trace.SpanStartOption{ trace.WithAttributes(attrs...), trace.WithSpanKind(trace.SpanKindProducer), } ctx, span := cfg.Tracer.Start(ctx, fmt.Sprintf("%s publish", msg.Topic), opts...) if version.IsAtLeast(sarama.V0_11_0_0) { // Inject current span context, so consumers can use it to propagate span. cfg.Propagators.Inject(ctx, carrier) } return span } func finishProducerSpan(span trace.Span, partition int32, offset int64, err error) { span.SetAttributes( semconv.MessagingMessageID(strconv.FormatInt(offset, 10)), semconv.MessagingKafkaDestinationPartition(int(partition)), ) if err != nil { span.SetStatus(codes.Error, err.Error()) } span.End() } producer_test.go000066400000000000000000000133331443314701600372770ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama import ( "testing" "time" "github.com/Shopify/sarama" "github.com/Shopify/sarama/mocks" "github.com/stretchr/testify/assert" oteltrace "go.opentelemetry.io/otel/trace" ) func TestAsyncProducer_ConcurrencyEdgeCases(t *testing.T) { cfg := newSaramaConfig() testCases := []struct { name string newAsyncProducer func(t *testing.T) sarama.AsyncProducer }{ { name: "original", newAsyncProducer: func(t *testing.T) sarama.AsyncProducer { return mocks.NewAsyncProducer(t, cfg) }, }, { name: "wrapped", newAsyncProducer: func(t *testing.T) sarama.AsyncProducer { var ap sarama.AsyncProducer = mocks.NewAsyncProducer(t, cfg) ap = WrapAsyncProducer(cfg, ap) return ap }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Run("closes Successes and Error after Close", func(t *testing.T) { timeout := time.NewTimer(time.Minute) defer timeout.Stop() p := tc.newAsyncProducer(t) p.Close() select { case <-timeout.C: t.Error("timeout - Successes channel was not closed") case _, ok := <-p.Successes(): if ok { t.Error("message was send to Successes channel instead of being closed") } } select { case <-timeout.C: t.Error("timeout - Errors channel was not closed") case _, ok := <-p.Errors(): if ok { t.Error("message was send to Errors channel instead of being closed") } } }) t.Run("closes Successes and Error after AsyncClose", func(t *testing.T) { timeout := time.NewTimer(time.Minute) defer timeout.Stop() p := tc.newAsyncProducer(t) p.AsyncClose() select { case <-timeout.C: t.Error("timeout - Successes channel was not closed") case _, ok := <-p.Successes(): if ok { t.Error("message was send to Successes channel instead of being closed") } } select { case <-timeout.C: t.Error("timeout - Errors channel was not closed") case _, ok := <-p.Errors(): if ok { t.Error("message was send to Errors channel instead of being closed") } } }) t.Run("panic when sending to Input after Close", func(t *testing.T) { p := tc.newAsyncProducer(t) p.Close() assert.Panics(t, func() { p.Input() <- &sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} }) }) t.Run("panic when sending to Input after AsyncClose", func(t *testing.T) { p := tc.newAsyncProducer(t) p.AsyncClose() assert.Panics(t, func() { p.Input() <- &sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} }) }) t.Run("panic when calling Close after AsyncClose", func(t *testing.T) { p := tc.newAsyncProducer(t) p.AsyncClose() assert.Panics(t, func() { p.Close() }) }) t.Run("panic when calling AsyncClose after Close", func(t *testing.T) { p := tc.newAsyncProducer(t) p.Close() assert.Panics(t, func() { p.AsyncClose() }) }) }) } } func newSaramaConfig() *sarama.Config { cfg := sarama.NewConfig() cfg.Version = sarama.V0_11_0_0 return cfg } func BenchmarkWrapSyncProducer(b *testing.B) { // Mock provider provider := oteltrace.NewNoopTracerProvider() cfg := newSaramaConfig() // Mock sync producer mockSyncProducer := mocks.NewSyncProducer(b, cfg) // Wrap sync producer syncProducer := WrapSyncProducer(cfg, mockSyncProducer, WithTracerProvider(provider)) message := sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockSyncProducer.ExpectSendMessageAndSucceed() _, _, err := syncProducer.SendMessage(&message) assert.NoError(b, err) } } func BenchmarkMockSyncProducer(b *testing.B) { cfg := newSaramaConfig() // Mock sync producer mockSyncProducer := mocks.NewSyncProducer(b, cfg) // Wrap sync producer syncProducer := mockSyncProducer message := sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockSyncProducer.ExpectSendMessageAndSucceed() _, _, err := syncProducer.SendMessage(&message) assert.NoError(b, err) } } func BenchmarkWrapAsyncProducer(b *testing.B) { // Mock provider provider := oteltrace.NewNoopTracerProvider() cfg := newSaramaConfig() cfg.Producer.Return.Successes = true mockAsyncProducer := mocks.NewAsyncProducer(b, cfg) // Wrap sync producer asyncProducer := WrapAsyncProducer(cfg, mockAsyncProducer, WithTracerProvider(provider)) message := sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockAsyncProducer.ExpectInputAndSucceed() asyncProducer.Input() <- &message <-asyncProducer.Successes() } } func BenchmarkMockAsyncProducer(b *testing.B) { cfg := newSaramaConfig() cfg.Producer.Return.Successes = true mockAsyncProducer := mocks.NewAsyncProducer(b, cfg) // Wrap sync producer asyncProducer := mockAsyncProducer message := sarama.ProducerMessage{Key: sarama.StringEncoder("foo")} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { mockAsyncProducer.ExpectInputAndSucceed() mockAsyncProducer.Input() <- &message <-asyncProducer.Successes() } } test/000077500000000000000000000000001443314701600350425ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsaramaconsumer_test.go000066400000000000000000000122701443314701600402650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "fmt" "testing" "github.com/Shopify/sarama" "github.com/Shopify/sarama/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) const ( topic = "test-topic" ) func TestWrapPartitionConsumer(t *testing.T) { propagators := propagation.TraceContext{} // Mock provider sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) // Mock partition consumer controller consumer := mocks.NewConsumer(t, sarama.NewConfig()) mockPartitionConsumer := consumer.ExpectConsumePartition(topic, 0, 0) // Create partition consumer partitionConsumer, err := consumer.ConsumePartition(topic, 0, 0) require.NoError(t, err) partitionConsumer = otelsarama.WrapPartitionConsumer(partitionConsumer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) consumeAndCheck(t, provider.Tracer("test"), sr.Ended, mockPartitionConsumer, partitionConsumer) } func TestWrapConsumer(t *testing.T) { propagators := propagation.TraceContext{} // Mock provider sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) // Mock partition consumer controller mockConsumer := mocks.NewConsumer(t, sarama.NewConfig()) mockPartitionConsumer := mockConsumer.ExpectConsumePartition(topic, 0, 0) // Wrap consumer consumer := otelsarama.WrapConsumer(mockConsumer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) // Create partition consumer partitionConsumer, err := consumer.ConsumePartition(topic, 0, 0) require.NoError(t, err) consumeAndCheck(t, provider.Tracer("test"), sr.Ended, mockPartitionConsumer, partitionConsumer) } func consumeAndCheck(t *testing.T, mt trace.Tracer, complFn func() []sdktrace.ReadOnlySpan, mockPartitionConsumer *mocks.PartitionConsumer, partitionConsumer sarama.PartitionConsumer) { // Create message with span context ctx, _ := mt.Start(context.Background(), "") message := sarama.ConsumerMessage{Key: []byte("foo")} propagators := propagation.TraceContext{} propagators.Inject(ctx, otelsarama.NewConsumerMessageCarrier(&message)) // Produce message mockPartitionConsumer.YieldMessage(&message) mockPartitionConsumer.YieldMessage(&sarama.ConsumerMessage{Key: []byte("foo2")}) // Consume messages msgList := make([]*sarama.ConsumerMessage, 2) msgList[0] = <-partitionConsumer.Messages() msgList[1] = <-partitionConsumer.Messages() require.NoError(t, partitionConsumer.Close()) // Wait for the channel to be closed <-partitionConsumer.Messages() // Check spans length spans := complFn() assert.Len(t, spans, 2) expectedList := []struct { attributeList []attribute.KeyValue parentSpanID trace.SpanID kind trace.SpanKind msgKey []byte }{ { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName("test-topic"), semconv.MessagingOperationReceive, semconv.MessagingMessageID("0"), semconv.MessagingKafkaSourcePartition(0), }, parentSpanID: trace.SpanContextFromContext(ctx).SpanID(), kind: trace.SpanKindConsumer, msgKey: []byte("foo"), }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName("test-topic"), semconv.MessagingOperationReceive, semconv.MessagingMessageID("1"), semconv.MessagingKafkaSourcePartition(0), }, kind: trace.SpanKindConsumer, msgKey: []byte("foo2"), }, } for i, expected := range expectedList { t.Run(fmt.Sprint("index", i), func(t *testing.T) { span := spans[i] assert.Equal(t, expected.parentSpanID, span.Parent().SpanID()) sc := trace.SpanContextFromContext(propagators.Extract(context.Background(), otelsarama.NewConsumerMessageCarrier(msgList[i]))) // propagators.Extract always returns a remote SpanContext. assert.Equal(t, sc, span.SpanContext().WithRemote(true)) assert.Equal(t, fmt.Sprintf("%s receive", topic), span.Name()) assert.Equal(t, expected.kind, span.SpanKind()) assert.Equal(t, expected.msgKey, msgList[i].Key) for _, k := range expected.attributeList { assert.Contains(t, span.Attributes(), k) } }) } } doc.go000066400000000000000000000017061443314701600361420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelsarama instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/test" go.mod000066400000000000000000000032411443314701600361500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/test go 1.19 require ( github.com/Shopify/sarama v1.38.1 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/eapache/go-resiliency v1.3.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.15.14 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama => ../ go.sum000066400000000000000000000211331443314701600361750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/testgithub.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0= github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9ndfrgrXUbOGObLHKBR4Fl3nZXwM2c7OYTT8hM= github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8= github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc= github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= producer_test.go000066400000000000000000000275131443314701600402630ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "errors" "fmt" "sync" "testing" "github.com/Shopify/sarama" "github.com/Shopify/sarama/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" oteltrace "go.opentelemetry.io/otel/trace" ) func TestWrapSyncProducer(t *testing.T) { propagators := propagation.TraceContext{} var err error // Mock provider sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) cfg := newSaramaConfig() // Mock sync producer mockSyncProducer := mocks.NewSyncProducer(t, cfg) // Wrap sync producer syncProducer := otelsarama.WrapSyncProducer(cfg, mockSyncProducer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) // Create message with span context ctx, _ := provider.Tracer("test").Start(context.Background(), "") messageWithSpanContext := sarama.ProducerMessage{Topic: topic, Key: sarama.StringEncoder("foo")} propagators.Inject(ctx, otelsarama.NewProducerMessageCarrier(&messageWithSpanContext)) // Expected expectedList := []struct { attributeList []attribute.KeyValue parentSpanID oteltrace.SpanID kind oteltrace.SpanKind }{ { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), semconv.MessagingMessageID("1"), semconv.MessagingKafkaDestinationPartition(0), }, parentSpanID: oteltrace.SpanContextFromContext(ctx).SpanID(), kind: oteltrace.SpanKindProducer, }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), semconv.MessagingMessageID("2"), semconv.MessagingKafkaDestinationPartition(0), }, kind: oteltrace.SpanKindProducer, }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), // TODO: The mock sync producer of sarama does not handle the offset while sending messages // https://github.com/Shopify/sarama/pull/1747 //semconv.MessagingMessageID("3"), semconv.MessagingKafkaDestinationPartition(12), }, kind: oteltrace.SpanKindProducer, }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), //semconv.MessagingMessageID("4"), semconv.MessagingKafkaDestinationPartition(25), }, kind: oteltrace.SpanKindProducer, }, } for i := 0; i < len(expectedList); i++ { mockSyncProducer.ExpectSendMessageAndSucceed() } // Send message msgList := []*sarama.ProducerMessage{ &messageWithSpanContext, {Topic: topic, Key: sarama.StringEncoder("foo2")}, {Topic: topic, Key: sarama.StringEncoder("foo3")}, {Topic: topic, Key: sarama.StringEncoder("foo4")}, } _, _, err = syncProducer.SendMessage(msgList[0]) require.NoError(t, err) _, _, err = syncProducer.SendMessage(msgList[1]) require.NoError(t, err) // Send messages require.NoError(t, syncProducer.SendMessages(msgList[2:])) spanList := sr.Ended() for i, expected := range expectedList { span := spanList[i] msg := msgList[i] // Check span assert.True(t, span.SpanContext().IsValid()) assert.Equal(t, expected.parentSpanID, span.Parent().SpanID()) assert.Equal(t, fmt.Sprintf("%s publish", topic), span.Name()) assert.Equal(t, expected.kind, span.SpanKind()) for _, k := range expected.attributeList { assert.Contains(t, span.Attributes(), k) } // Check tracing propagation remoteSpanFromMessage := oteltrace.SpanContextFromContext(propagators.Extract(context.Background(), otelsarama.NewProducerMessageCarrier(msg))) assert.True(t, remoteSpanFromMessage.IsValid()) } } func TestWrapAsyncProducer(t *testing.T) { propagators := propagation.TraceContext{} // Create message with span context createMessages := func(mt oteltrace.Tracer) []*sarama.ProducerMessage { ctx, _ := mt.Start(context.Background(), "") messageWithSpanContext := sarama.ProducerMessage{Topic: topic, Key: sarama.StringEncoder("foo")} propagators.Inject(ctx, otelsarama.NewProducerMessageCarrier(&messageWithSpanContext)) return []*sarama.ProducerMessage{ &messageWithSpanContext, {Topic: topic, Key: sarama.StringEncoder("foo2")}, } } t.Run("without successes config", func(t *testing.T) { // Mock provider sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) cfg := newSaramaConfig() mockAsyncProducer := mocks.NewAsyncProducer(t, cfg) ap := otelsarama.WrapAsyncProducer(cfg, mockAsyncProducer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) msgList := createMessages(provider.Tracer("test")) // Send message for _, msg := range msgList { mockAsyncProducer.ExpectInputAndSucceed() ap.Input() <- msg } err := ap.Close() require.NoError(t, err) spanList := sr.Ended() // Expected expectedList := []struct { attributeList []attribute.KeyValue kind oteltrace.SpanKind }{ { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), }, kind: oteltrace.SpanKindProducer, }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), }, kind: oteltrace.SpanKindProducer, }, } for i, expected := range expectedList { span := spanList[i] msg := msgList[i] // Check span assert.True(t, span.SpanContext().IsValid()) assert.Equal(t, fmt.Sprintf("%s publish", topic), span.Name()) assert.Equal(t, expected.kind, span.SpanKind()) for _, k := range expected.attributeList { assert.Contains(t, span.Attributes(), k) } // Check tracing propagation remoteSpanFromMessage := oteltrace.SpanContextFromContext(propagators.Extract(context.Background(), otelsarama.NewProducerMessageCarrier(msg))) assert.True(t, remoteSpanFromMessage.IsValid()) } }) t.Run("with successes config", func(t *testing.T) { // Mock provider sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) // Set producer with successes config cfg := newSaramaConfig() cfg.Producer.Return.Successes = true mockAsyncProducer := mocks.NewAsyncProducer(t, cfg) ap := otelsarama.WrapAsyncProducer(cfg, mockAsyncProducer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) msgList := createMessages(provider.Tracer("test")) // Send message for i, msg := range msgList { mockAsyncProducer.ExpectInputAndSucceed() // Add metadata to msg msg.Metadata = i ap.Input() <- msg newMsg := <-ap.Successes() assert.Equal(t, newMsg, msg) } err := ap.Close() require.NoError(t, err) spanList := sr.Ended() // Expected expectedList := []struct { attributeList []attribute.KeyValue kind oteltrace.SpanKind }{ { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), semconv.MessagingMessageID("1"), semconv.MessagingKafkaDestinationPartition(9), }, kind: oteltrace.SpanKindProducer, }, { attributeList: []attribute.KeyValue{ semconv.MessagingSystem("kafka"), semconv.MessagingDestinationKindTopic, semconv.MessagingDestinationName(topic), semconv.MessagingMessageID("2"), semconv.MessagingKafkaDestinationPartition(31), }, kind: oteltrace.SpanKindProducer, }, } for i, expected := range expectedList { span := spanList[i] msg := msgList[i] // Check span assert.True(t, span.SpanContext().IsValid()) assert.Equal(t, fmt.Sprintf("%s publish", topic), span.Name()) assert.Equal(t, expected.kind, span.SpanKind()) for _, k := range expected.attributeList { assert.Contains(t, span.Attributes(), k) } // Check metadata assert.Equal(t, i, msg.Metadata) // Check tracing propagation remoteSpanFromMessage := oteltrace.SpanContextFromContext(propagators.Extract(context.Background(), otelsarama.NewProducerMessageCarrier(msg))) assert.True(t, remoteSpanFromMessage.IsValid()) } }) } func TestWrapAsyncProducerError(t *testing.T) { propagators := propagation.TraceContext{} // Mock provider sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) // Set producer with successes config cfg := newSaramaConfig() cfg.Producer.Return.Successes = true mockAsyncProducer := mocks.NewAsyncProducer(t, cfg) ap := otelsarama.WrapAsyncProducer(cfg, mockAsyncProducer, otelsarama.WithTracerProvider(provider), otelsarama.WithPropagators(propagators)) mockAsyncProducer.ExpectInputAndFail(errors.New("test")) metadata := "test metadata" ap.Input() <- &sarama.ProducerMessage{Topic: topic, Key: sarama.StringEncoder("foo2"), Metadata: metadata} err := <-ap.Errors() require.Error(t, err) assert.Equal(t, metadata, err.Msg.Metadata, "should preseve metadata") ap.AsyncClose() spanList := sr.Ended() assert.Len(t, spanList, 1) span := spanList[0] assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, "test", span.Status().Description) } func TestWrapAsyncProducer_DrainsSuccessesAndErrorsChannels(t *testing.T) { // Mock provider sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) // Set producer with successes config and fill it with successes and errors cfg := newSaramaConfig() cfg.Producer.Return.Successes = true mockAsyncProducer := mocks.NewAsyncProducer(t, cfg) ap := otelsarama.WrapAsyncProducer(cfg, mockAsyncProducer, otelsarama.WithTracerProvider(provider)) wantSuccesses := 5 for i := 0; i < wantSuccesses; i++ { mockAsyncProducer.ExpectInputAndSucceed() ap.Input() <- &sarama.ProducerMessage{Topic: topic, Key: sarama.StringEncoder("foo2")} } wantErrros := 3 for i := 0; i < wantErrros; i++ { mockAsyncProducer.ExpectInputAndFail(errors.New("test")) ap.Input() <- &sarama.ProducerMessage{Topic: topic, Key: sarama.StringEncoder("foo2")} } ap.AsyncClose() // Ensure it is possible to read Successes and Errors after AsyncClose var wg sync.WaitGroup gotSuccesses := 0 wg.Add(1) go func() { defer wg.Done() for range ap.Successes() { gotSuccesses++ } }() gotErrors := 0 wg.Add(1) go func() { defer wg.Done() for range ap.Errors() { gotErrors++ } }() wg.Wait() spanList := sr.Ended() assert.Equal(t, wantSuccesses, gotSuccesses, "should read all successes") assert.Equal(t, wantErrros, gotErrors, "should read all errors") assert.Len(t, spanList, wantSuccesses+wantErrros, "should record all spans") } func newSaramaConfig() *sarama.Config { cfg := sarama.NewConfig() cfg.Version = sarama.V0_11_0_0 return cfg } version.go000066400000000000000000000020651443314701600370610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/test" // Version is the current release version of the sarama instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020521443314701600360760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/Shopify/sarama/otelsarama// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelsarama // import "go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama" // Version is the current release version of the sarama instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/000077500000000000000000000000001443314701600305635ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/000077500000000000000000000000001443314701600316445ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/000077500000000000000000000000001443314701600336115ustar00rootroot00000000000000beego.go000066400000000000000000000116141443314701600351450ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" import ( "context" "net/http" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/internal" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/trace" "github.com/astaxie/beego" ) // Handler implements the http.Handler interface and provides // trace and metrics to beego web apps. type Handler struct { http.Handler } // ServerHTTP calls the configured handler to serve HTTP for req to rr. func (o *Handler) ServeHTTP(rr http.ResponseWriter, req *http.Request) { ctx := beego.BeeApp.Handlers.GetContext() defer beego.BeeApp.Handlers.GiveBackContext(ctx) ctx.Reset(rr, req) // use the beego context to try to find a route template if router, found := beego.BeeApp.Handlers.FindRouter(ctx); found { // if found, save it to the context reqCtx := context.WithValue(req.Context(), internal.CtxRouteTemplateKey, router.GetPattern()) req = req.WithContext(reqCtx) } o.Handler.ServeHTTP(rr, req) } // defaultSpanNameFormatter is the default formatter for spans created with the beego // integration. Returns the route path template, or the URL path if the current path // is not associated with a router. func defaultSpanNameFormatter(_ string, req *http.Request) string { if val := req.Context().Value(internal.CtxRouteTemplateKey); val != nil { str, ok := val.(string) if ok { return str } } return req.Method } // NewOTelBeegoMiddleWare creates a MiddleWare that provides OpenTelemetry // tracing and metrics to a Beego web app. // Parameter service should describe the name of the (virtual) server handling the request. // The OTelBeegoMiddleWare can be configured using the provided Options. func NewOTelBeegoMiddleWare(service string, options ...Option) beego.MiddleWare { cfg := newConfig(options...) httpOptions := []otelhttp.Option{ otelhttp.WithTracerProvider(cfg.tracerProvider), otelhttp.WithMeterProvider(cfg.meterProvider), otelhttp.WithPropagators(cfg.propagators), otelhttp.WithServerName(service), } for _, f := range cfg.filters { httpOptions = append( httpOptions, otelhttp.WithFilter(otelhttp.Filter(f)), ) } if cfg.formatter != nil { httpOptions = append(httpOptions, otelhttp.WithSpanNameFormatter(cfg.formatter)) } return func(handler http.Handler) http.Handler { return &Handler{ otelhttp.NewHandler( handler, "", httpOptions..., ), } } } // Render traces beego.Controller.Render. Use this function // if you want to add a child span for the rendering of a template file. // Disable autorender before use, and call this function explicitly. func Render(c *beego.Controller) error { _, span := span(c, internal.RenderTemplateSpanName) defer span.End() err := c.Render() if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "template failure") } return err } // RenderString traces beego.Controller.RenderString. Use this function // if you want to add a child span for the rendering of a template file to // its string representation. // Disable autorender before use, and call this function explicitly. func RenderString(c *beego.Controller) (string, error) { _, span := span(c, internal.RenderStringSpanName) defer span.End() str, err := c.RenderString() if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "render string failure") } return str, err } // RenderBytes traces beego.Controller.RenderBytes. Use this function if // you want to add a child span for the rendering of a template file to its // byte representation. // Disable autorender before use, and call this function explicitly. func RenderBytes(c *beego.Controller) ([]byte, error) { _, span := span(c, internal.RenderBytesSpanName) defer span.End() bytes, err := c.RenderBytes() if err != nil { span.RecordError(err) span.SetStatus(codes.Error, "render bytes failure") } return bytes, err } func span(c *beego.Controller, spanName string) (context.Context, trace.Span) { ctx := c.Ctx.Request.Context() span := trace.SpanFromContext(ctx) tracer := span.TracerProvider().Tracer("go.opentelemetry.io/contrib/instrumentation/github/astaxie/beego/otelbeego") return tracer.Start( ctx, spanName, trace.WithAttributes( Template(c.TplName), ), ) } beego_test.go000066400000000000000000000060541443314701600362060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego import ( "context" "net/http" "net/http/httptest" "testing" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" "github.com/astaxie/beego" beegoCtx "github.com/astaxie/beego/context" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const middleWareName = "test-router" func replaceBeego() { beego.BeeApp = beego.NewApp() } func ctxTest() (context.Context, func(*testing.T, context.Context)) { ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, Remote: true, }) ctx = trace.ContextWithSpanContext(ctx, sc) return ctx, func(t *testing.T, ctx context.Context) { got := trace.SpanContextFromContext(ctx) assert.Equal(t, sc.TraceID(), got.TraceID()) assert.Equal(t, sc.SpanID(), got.SpanID()) assert.Equal(t, sc.TraceFlags(), got.TraceFlags()) assert.Equal(t, sc.TraceState(), got.TraceState()) assert.Equal(t, sc.IsRemote(), got.IsRemote()) } } func TestSpanFromContextDefaultProvider(t *testing.T) { defer replaceBeego() provider := noop.NewMeterProvider() otel.SetMeterProvider(provider) otel.SetTracerProvider(trace.NewNoopTracerProvider()) ctx, eval := ctxTest() router := beego.NewControllerRegister() router.Get("/hello-with-span", func(ctx *beegoCtx.Context) { eval(t, ctx.Request.Context()) ctx.ResponseWriter.WriteHeader(http.StatusAccepted) }) rr := httptest.NewRecorder() req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost/hello-with-span", nil) require.NoError(t, err) mw := NewOTelBeegoMiddleWare(middleWareName) mw(router).ServeHTTP(rr, req) require.Equal(t, http.StatusAccepted, rr.Result().StatusCode) } func TestSpanFromContextCustomProvider(t *testing.T) { defer replaceBeego() provider := noop.NewMeterProvider() ctx, eval := ctxTest() router := beego.NewControllerRegister() router.Get("/hello-with-span", func(ctx *beegoCtx.Context) { eval(t, ctx.Request.Context()) ctx.ResponseWriter.WriteHeader(http.StatusAccepted) }) rr := httptest.NewRecorder() req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost/hello-with-span", nil) require.NoError(t, err) mw := NewOTelBeegoMiddleWare( middleWareName, WithTracerProvider(trace.NewNoopTracerProvider()), WithMeterProvider(provider), ) mw(router).ServeHTTP(rr, req) require.Equal(t, http.StatusAccepted, rr.Result().StatusCode) } common.go000066400000000000000000000025641443314701600353600ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" import ( "net/http" "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/internal" "go.opentelemetry.io/otel/attribute" ) // ------------------------------------------ Attribute Functions // Template returns the template name as a KeyValue pair. func Template(name string) attribute.KeyValue { return internal.TemplateKey.String(name) } // ------------------------------------------ OTel HTTP Types // Filter returns true if the request should be traced. type Filter func(*http.Request) bool // SpanNameFormatter creates a custom span name from the operation and request object. type SpanNameFormatter func(operation string, req *http.Request) string config.go000066400000000000000000000063671443314701600353420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) // config provides configuration for the beego OpenTelemetry // middleware. Configuration is modified using the provided Options. type config struct { tracerProvider trace.TracerProvider meterProvider metric.MeterProvider propagators propagation.TextMapPropagator filters []Filter formatter SpanNameFormatter } // Option applies a configuration to the given config. type Option interface { apply(*config) } // optionFunc is a function type that applies a particular // configuration to the beego middleware in question. type optionFunc func(c *config) // Apply will apply the option to the config, c. func (o optionFunc) apply(c *config) { o(c) } // ------------------------------------------ Options // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.tracerProvider = provider } }) } // WithMeterProvider specifies a meter provider to use for creating a meter. // If none is specified, the global provider is used. func WithMeterProvider(provider metric.MeterProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.meterProvider = provider } }) } // WithPropagators sets the propagators used in the middleware. // Defaults to global.Propagators(). func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(c *config) { if propagators != nil { c.propagators = propagators } }) } // WithFilter adds the given filter for use in the middleware. // Defaults to no filters. func WithFilter(f Filter) Option { return optionFunc(func(c *config) { c.filters = append(c.filters, f) }) } // WithSpanNameFormatter sets the formatter to be used to format // span names. Defaults to the path template. func WithSpanNameFormatter(f SpanNameFormatter) Option { return optionFunc(func(c *config) { c.formatter = f }) } // ------------------------------------------ Private Functions func newConfig(options ...Option) *config { config := &config{ tracerProvider: otel.GetTracerProvider(), meterProvider: otel.GetMeterProvider(), propagators: otel.GetTextMapPropagator(), filters: []Filter{}, formatter: defaultSpanNameFormatter, } for _, option := range options { option.apply(config) } return config } doc.go000066400000000000000000000014121443314701600346240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelbeego instruments the github.com/astaxie/beego package. package otelbeego // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" example/000077500000000000000000000000001443314701600351655ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeegoDockerfile000066400000000000000000000015651443314701600371660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/astaxie/beego/otelbeego/example FROM base AS example-beego-server RUN go install ./server/server.go CMD ["/go/bin/server"] FROM base AS example-http-client RUN go install ./client/client.go CMD ["/go/bin/client"] README.md000066400000000000000000000015601443314701600364460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example# Beego Server Instrumentation Example An HTTP client connects to a Beego server. They both generate span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `beego-server` and `http-client` services to run the example: ```sh docker-compose up -d ``` The `http-client` service sends just one HTTP request to `beego-server` and then exits. View the span generated by `beego-server` in the logs: ```sh docker-compose logs beego-server ``` You can also visit a webpage hosted by the Beego app by navigating to `http://localhost:7777` in your browser. Two spans are created this time, one for the HTTP request, and another for rendering the template HTML. You can view the spans the same way as above. Shut down the services when you are finished with the example: ```sh docker-compose down ``` client/000077500000000000000000000000001443314701600364435ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/exampleclient.go000066400000000000000000000021471443314701600402540ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example/client// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "flag" "fmt" "io" "log" "net/http" ) func main() { url := flag.String("server", "http://localhost:7777/hello", "server url") flag.Parse() client := http.Client{} req, err := http.NewRequest("GET", *url, nil) if err != nil { log.Fatal(err) } fmt.Printf("sending request...\n") res, err := client.Do(req) if err != nil { log.Fatal(err) } body, err := io.ReadAll(res.Body) if err != nil { log.Fatal(err) } _ = res.Body.Close() fmt.Printf("Response Received: %s\n\n\n", body) } docker-compose.yml000066400000000000000000000020551443314701600406240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: beego-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. target: example-beego-server command: ["/go/bin/server", "-zipkin", "zipkin:9411"] ports: - 7777:7777 http-client: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. target: example-http-client command: ["/go/bin/client", "-server", "http://beego-server:7777/hello"] depends_on: - beego-server go.mod000066400000000000000000000032251443314701600362750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego => ../ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../../../../../net/http/otelhttp ) require ( github.com/astaxie/beego v1.12.3 go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) go.sum000066400000000000000000000505321443314701600363250ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/examplegithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ= github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server/000077500000000000000000000000001443314701600364735ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/exampleserver.go000066400000000000000000000054121443314701600403320ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example/server// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "github.com/astaxie/beego" "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) type exampleController struct { beego.Controller } func (c *exampleController) Get() { ctx := c.Ctx.Request.Context() span := trace.SpanFromContext(ctx) span.AddEvent("handling this...") c.Ctx.WriteString("Hello, world!") } func (c *exampleController) Template() { c.TplName = "hello.tpl" // Render the template file with tracing enabled if err := otelbeego.Render(&c.Controller); err != nil { c.Abort("500") } } func initTracer() (*sdktrace.TracerProvider, error) { // Create stdout exporter to be able to retrieve // the collected spans. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // For the demonstration, use sdktrace.AlwaysSample sampler to sample all traces. // In a production application, use sdktrace.ProbabilitySampler with a desired probability. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName("ExampleService")))) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() // To enable tracing on template rendering, disable autorender beego.BConfig.WebConfig.AutoRender = false beego.Router("/hello", &exampleController{}) beego.Router("/", &exampleController{}, "get:Template") mware := otelbeego.NewOTelBeegoMiddleWare("beego-example") beego.RunWithMiddleWares(":7777", mware) } views/000077500000000000000000000000001443314701600363225ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/examplehello.tpl000066400000000000000000000003121443314701600401420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/example/views Hello World Welcome to the beego instrumentation example! example_middleware_test.go000066400000000000000000000023751443314701600407570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego import ( "github.com/astaxie/beego" ) type ExampleController struct { beego.Controller } func (c *ExampleController) Get() { // name of the template in the views directory c.TplName = "index.tpl" // explicit call to Render if err := Render(&c.Controller); err != nil { c.Abort("500") } } func ExampleRender() { // Init the trace and meter provider // Disable autorender beego.BConfig.WebConfig.AutoRender = false // Create routes beego.Router("/", &ExampleController{}) // Create the middleware mware := NewOTelBeegoMiddleWare("exampe-server") // Start the server using the OTel middleware beego.RunWithMiddleWares(":7777", mware) } go.mod000066400000000000000000000030671443314701600346460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeegomodule go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego go 1.19 replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../../../../net/http/otelhttp require ( github.com/astaxie/beego v1.12.3 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000503161443314701600346720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeegogithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ= github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= internal/000077500000000000000000000000001443314701600353465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeegocommon.go000066400000000000000000000030571443314701600371720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/internal// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/internal" import ( "go.opentelemetry.io/otel/attribute" ) // ContextKey is a key for a value in a context.Context, // used as it is not recommended to use basic types as keys. type ContextKey string const ( // CtxRouteTemplateKey is the context key used for a route template. CtxRouteTemplateKey = ContextKey("x-opentelemetry-route-template") // RenderTemplateSpanName is the span name for the beego.Controller.Render // operation. RenderTemplateSpanName = "beego.render.template" // RenderStringSpanName is the span name for the // beego.Controller.RenderString operation. RenderStringSpanName = "beego.render.string" // RenderStringSpanName is the span name for the // beego.Controller.RenderBytes operation. RenderBytesSpanName = "beego.render.bytes" // TemplateKey is used to describe the beego template used. TemplateKey = attribute.Key("go.template") ) test/000077500000000000000000000000001443314701600345115ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeegobeego_test.go000066400000000000000000000354101443314701600371630ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "time" "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/internal" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "github.com/astaxie/beego" beegoCtx "github.com/astaxie/beego/context" assetfs "github.com/elazarl/go-bindata-assetfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TODO(#2762): Add metric integration tests for the instrumentation. These // tests depend on // https://github.com/open-telemetry/opentelemetry-go/issues/3031 being // resolved. // ------------------------------------------ Test Controller const defaultReply = "hello world" var tplName = "" type testReply struct { Message string `json:"message"` Err string `json:"error"` } type testController struct { beego.Controller T *testing.T } func (c *testController) Get() { reply := &testReply{ Message: defaultReply, } c.Data["json"] = reply c.ServeJSON() } func (c *testController) Post() { name := c.GetString("name") var reply *testReply if name == "" { c.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest) reply = &testReply{ Err: "missing query param \"name\"", } } else { reply = &testReply{ Message: fmt.Sprintf("%s said hello.", name), } } c.Data["json"] = reply c.ServeJSON() } func (c *testController) Delete() { reply := &testReply{ Message: "success", } c.Ctx.ResponseWriter.WriteHeader(http.StatusAccepted) c.Data["json"] = reply c.ServeJSON() } func (c *testController) Put() { reply := &testReply{ Message: "successfully put", } c.Ctx.ResponseWriter.WriteHeader(http.StatusAccepted) c.Data["json"] = reply c.ServeJSON() } func (c *testController) TemplateRender() { c.TplName = tplName c.Data["name"] = "test" require.NoError(c.T, otelbeego.Render(&c.Controller)) } func (c *testController) TemplateRenderString() { c.TplName = tplName c.Data["name"] = "test" str, err := otelbeego.RenderString(&c.Controller) require.NoError(c.T, err) c.Ctx.WriteString(str) } func (c *testController) TemplateRenderBytes() { c.TplName = tplName c.Data["name"] = "test" bytes, err := otelbeego.RenderBytes(&c.Controller) require.NoError(c.T, err) _, err = c.Ctx.ResponseWriter.Write(bytes) require.NoError(c.T, err) } func addTestRoutes(t *testing.T) { controller := &testController{ T: t, } beego.Router("/", controller) beego.Router("/:id", controller) beego.Router("/greet", controller) beego.Router("/template/render", controller, "get:TemplateRender") beego.Router("/template/renderstring", controller, "get:TemplateRenderString") beego.Router("/template/renderbytes", controller, "get:TemplateRenderBytes") router := beego.NewNamespace("/api", beego.NSNamespace("/v1", beego.NSRouter("/", controller), beego.NSRouter("/:id", controller), beego.NSRouter("/greet", controller), ), ) beego.AddNamespace(router) } func replaceBeego() { beego.BeeApp = beego.NewApp() } // ------------------------------------------ Unit Tests func TestHandler(t *testing.T) { for _, tcase := range testCases { tc := *tcase t.Run(tc.name, func(t *testing.T) { runTest(t, &tc, "http://localhost") }) } } func TestHandlerWithNamespace(t *testing.T) { for _, tcase := range testCases { tc := *tcase t.Run(tc.name, func(t *testing.T) { // if using default span name, change name to NS path if tc.expectedSpanName != customSpanName { tc.expectedSpanName = fmt.Sprintf("/api/v1%s", tc.expectedSpanName) } runTest(t, &tc, "http://localhost/api/v1") }) } } func TestWithFilters(t *testing.T) { for _, tcase := range testCases { tc := *tcase t.Run(tc.name, func(t *testing.T) { wasCalled := false beego.InsertFilter("/*", beego.BeforeRouter, func(ctx *beegoCtx.Context) { wasCalled = true }) runTest(t, &tc, "http://localhost") require.True(t, wasCalled) }) } } func TestStatic(t *testing.T) { defer replaceBeego() sr := tracetest.NewSpanRecorder() tracerProvider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) file, err := os.CreateTemp("", "static-*.html") require.NoError(t, err) defer file.Close() defer os.Remove(file.Name()) _, err = file.WriteString(beego.Htmlunquote("

Hello, world!

")) require.NoError(t, err) beego.SetStaticPath("/", file.Name()) defer beego.SetStaticPath("/", "") mw := otelbeego.NewOTelBeegoMiddleWare(middleWareName, otelbeego.WithTracerProvider(tracerProvider), ) rr := httptest.NewRecorder() req, err := http.NewRequest(http.MethodGet, "http://localhost/", nil) require.NoError(t, err) mw(beego.BeeApp.Handlers).ServeHTTP(rr, req) tc := &testCase{ expectedSpanName: "GET", expectedAttributes: defaultAttributes(), } require.Equal(t, http.StatusOK, rr.Result().StatusCode) body, err := io.ReadAll(rr.Result().Body) require.NoError(t, err) require.Equal(t, "

Hello, world!

", string(body)) spans := sr.Ended() require.Len(t, spans, 1) assertSpan(t, spans[0], tc) } var htmlStr = ` Hello World This is a template test. Hello {{.name}} ` func TestRender(t *testing.T) { tplName = "index.tpl" beego.SetTemplateFSFunc(func() http.FileSystem { return &assetfs.AssetFS{ Asset: func(path string) ([]byte, error) { if _, f := filepath.Split(path); f == tplName { return []byte(htmlStr), nil } return nil, os.ErrNotExist }, AssetDir: func(path string) ([]string, error) { switch path { case "", `\`: return []string{tplName}, nil } return nil, os.ErrNotExist }, AssetInfo: func(path string) (os.FileInfo, error) { if _, f := filepath.Split(path); f == tplName { return &assetfs.FakeFile{ Path: path, Len: int64(len(htmlStr)), Timestamp: time.Now(), }, nil } return nil, os.ErrNotExist }, } }) viewPath := "/" require.NoError(t, beego.AddViewPath(viewPath)) ctrl := &testController{ Controller: beego.Controller{ ViewPath: viewPath, EnableRender: true, }, T: t, } app := beego.NewApp() app.Handlers.Add("/template/render", ctrl, "get:TemplateRender") app.Handlers.Add("/template/renderstring", ctrl, "get:TemplateRenderString") app.Handlers.Add("/template/renderbytes", ctrl, "get:TemplateRenderBytes") sr := tracetest.NewSpanRecorder() tracerProvider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) mw := otelbeego.NewOTelBeegoMiddleWare( middleWareName, otelbeego.WithTracerProvider(tracerProvider), ) for _, str := range []string{"/render", "/renderstring", "/renderbytes"} { rr := httptest.NewRecorder() req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://localhost/template%s", str), nil) require.NoError(t, err) mw(app.Handlers).ServeHTTP(rr, req) body, err := io.ReadAll(rr.Result().Body) require.Equal(t, strings.Replace(htmlStr, "{{.name}}", "test", 1), string(body)) require.NoError(t, err) } spans := sr.Ended() require.Len(t, spans, 6) // 3 HTTP requests, each creating 2 spans for _, span := range spans { switch span.Name() { case "GET": continue case internal.RenderTemplateSpanName, internal.RenderStringSpanName, internal.RenderBytesSpanName: assert.Contains(t, span.Attributes(), internal.TemplateKey.String(tplName)) default: t.Fatal("unexpected span name", span.Name()) } } } // ------------------------------------------ Utilities func runTest(t *testing.T, tc *testCase, url string) { sr := tracetest.NewSpanRecorder() tracerProvider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) addTestRoutes(t) defer replaceBeego() rr := httptest.NewRecorder() req, err := http.NewRequest( tc.method, fmt.Sprintf("%s%s", url, tc.path), nil, ) require.NoError(t, err) tc.expectedAttributes = append(tc.expectedAttributes, defaultAttributes()...) mw := otelbeego.NewOTelBeegoMiddleWare( middleWareName, append( tc.options, otelbeego.WithTracerProvider(tracerProvider), )..., ) mw(beego.BeeApp.Handlers).ServeHTTP(rr, req) require.Equal(t, tc.expectedHTTPStatus, rr.Result().StatusCode) body, err := io.ReadAll(rr.Result().Body) require.NoError(t, err) message := testReply{} require.NoError(t, json.Unmarshal(body, &message)) require.Equal(t, tc.expectedResponse, message) spans := sr.Ended() if tc.hasSpan { require.Len(t, spans, 1) assertSpan(t, spans[0], tc) } else { require.Len(t, spans, 0) } } func defaultAttributes() []attribute.KeyValue { return []attribute.KeyValue{ semconv.NetHostName(middleWareName), semconv.HTTPSchemeHTTP, } } func assertSpan(t *testing.T, span trace.ReadOnlySpan, tc *testCase) { require.Equal(t, tc.expectedSpanName, span.Name()) attr := span.Attributes() for _, att := range tc.expectedAttributes { assert.Contains(t, attr, att) } } // ------------------------------------------ Test Cases const middleWareName = "test-router" const customSpanName = "Test span name" type testCase struct { name string method string path string options []otelbeego.Option hasSpan bool expectedSpanName string expectedHTTPStatus int expectedResponse testReply expectedAttributes []attribute.KeyValue } var testCases = []*testCase{ { name: "GET/__All default options", method: http.MethodGet, path: "/", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/", expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: defaultReply}, expectedAttributes: []attribute.KeyValue{}, }, { name: "GET/1__All default options", method: http.MethodGet, path: "/1", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/:id", expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: defaultReply}, expectedAttributes: []attribute.KeyValue{}, }, { name: "POST/greet?name=test__All default options", method: http.MethodPost, path: "/greet?name=test", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/greet", expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: "test said hello."}, expectedAttributes: []attribute.KeyValue{}, }, { name: "DELETE/__All default options", method: http.MethodDelete, path: "/", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/", expectedHTTPStatus: http.StatusAccepted, expectedResponse: testReply{Message: "success"}, expectedAttributes: []attribute.KeyValue{}, }, { name: "PUT/__All default options", method: http.MethodPut, path: "/", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/", expectedHTTPStatus: http.StatusAccepted, expectedResponse: testReply{Message: "successfully put"}, expectedAttributes: []attribute.KeyValue{}, }, { name: "GET/__Custom propagators", method: http.MethodGet, path: "/", options: []otelbeego.Option{ otelbeego.WithPropagators(propagation.NewCompositeTextMapPropagator(b3.New())), }, hasSpan: true, expectedSpanName: "/", expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: defaultReply}, expectedAttributes: []attribute.KeyValue{}, }, { name: "GET/__Custom filter filtering route", method: http.MethodGet, path: "/", options: []otelbeego.Option{ otelbeego.WithFilter(otelbeego.Filter(func(req *http.Request) bool { return req.URL.Path != "/" })), otelbeego.WithFilter(otelbeego.Filter(func(req *http.Request) bool { return req.URL.Path != "/api/v1/" })), }, hasSpan: false, expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: defaultReply}, }, { name: "GET/__Custom filter not filtering route", method: http.MethodGet, path: "/", options: []otelbeego.Option{ otelbeego.WithFilter(otelbeego.Filter(func(req *http.Request) bool { return req.URL.Path != "/greet" })), }, hasSpan: true, expectedSpanName: "/", expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: defaultReply}, expectedAttributes: []attribute.KeyValue{}, }, { name: "POST/greet__Default options, bad request", method: http.MethodPost, path: "/greet", options: []otelbeego.Option{}, hasSpan: true, expectedSpanName: "/greet", expectedHTTPStatus: http.StatusBadRequest, expectedResponse: testReply{Err: "missing query param \"name\""}, expectedAttributes: []attribute.KeyValue{}, }, { name: "POST/greet?name=test__Custom span name formatter", method: http.MethodPost, path: "/greet?name=test", options: []otelbeego.Option{ otelbeego.WithSpanNameFormatter(otelbeego.SpanNameFormatter(func(opp string, req *http.Request) string { return customSpanName })), }, hasSpan: true, expectedSpanName: customSpanName, expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: "test said hello."}, expectedAttributes: []attribute.KeyValue{}, }, { name: "POST/greet?name=test__Custom span name formatter and custom filter", method: http.MethodPost, path: "/greet?name=test", options: []otelbeego.Option{ otelbeego.WithFilter(otelbeego.Filter(func(req *http.Request) bool { return !strings.Contains(req.URL.Path, "greet") })), otelbeego.WithSpanNameFormatter(otelbeego.SpanNameFormatter(func(opp string, req *http.Request) string { return customSpanName })), }, hasSpan: false, expectedHTTPStatus: http.StatusOK, expectedResponse: testReply{Message: "test said hello."}, expectedAttributes: []attribute.KeyValue{}, }, } doc.go000066400000000000000000000017031443314701600356060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelbeego instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/test" go.mod000066400000000000000000000036721443314701600356270ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/test go 1.19 require ( github.com/astaxie/beego v1.12.3 github.com/elazarl/go-bindata-assetfs v1.0.1 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego v0.42.0 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace ( go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego => ../ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../../../../../net/http/otelhttp go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) go.sum000066400000000000000000000506041443314701600356510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/testgithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ= github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020621443314701600365250ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/test" // Version is the current release version of the Beego instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020461443314701600355500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/astaxie/beego/otelbeego// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelbeego // import "go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego" // Version is the current release version of the Beego instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/000077500000000000000000000000001443314701600277175ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/000077500000000000000000000000001443314701600323325ustar00rootroot00000000000000otellambda/000077500000000000000000000000001443314701600343575ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-goREADME.md000066400000000000000000000113771443314701600356470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda# OpenTelemetry AWS Lambda Instrumentation for Golang [![Go Reference][goref-image]][goref-url] [![Apache License][license-image]][license-url] This module provides instrumentation for [`AWS Lambda`](https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html). ## Installation ```bash go get -u go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda ``` ## example See [./example](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/aws/aws-lambda-go/otellambda/example) ## Usage Create a sample Lambda Go application such as below. ```go package main import ( "context" "fmt" "github.com/aws/aws-lambda-go/lambda" ) type MyEvent struct { Name string `json:"name"` } func HandleRequest(ctx context.Context, name MyEvent) (string, error) { return fmt.Sprintf("Hello %s!", name.Name ), nil } func main() { lambda.Start(HandleRequest) } ``` Now use the provided wrapper to instrument your basic Lambda function: ```go // Add import import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" // wrap lambda handler function func main() { lambda.Start(otellambda.InstrumentHandler(HandleRequest)) } ``` ## AWS Lambda Instrumentation Options | Options | Input Type | Description | Default | | --- | --- | --- | --- | | `WithTracerProvider` | `trace.TracerProvider` | Provide a custom `TracerProvider` for creating spans. Consider using the [AWS Lambda Resource Detector][lambda-detector-url] with your tracer provider to improve tracing information. | `otel.GetTracerProvider()` | `WithFlusher` | `otellambda.Flusher` | This instrumentation will call the `ForceFlush` method of its `Flusher` at the end of each invocation. Should you be using asynchronous logic (such as `sddktrace's BatchSpanProcessor`) it is very import for spans to be `ForceFlush`'ed before [Lambda freezes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html) to avoid data delays. | `Flusher` with noop `ForceFlush` | `WithEventToCarrier` | `func(eventJSON []byte) propagation.TextMapCarrier{}` | Function for providing custom logic to support retrieving trace header from different event types that are handled by AWS Lambda (e.g., SQS, CloudWatch, Kinesis, API Gateway) and returning them in a `propagation.TextMapCarrier` which a Propagator can use to extract the trace header into the context. | Function which returns an empty `TextMapCarrier` - new spans will be part of a new Trace and have no parent past Lambda instrumentation span | `WithPropagator` | `propagation.Propagator` | The `Propagator` the instrumentation will use to extract trace information into the context. | `otel.GetTextMapPropagator()` | ### Usage With Options Example ```go var someHeaderKey = "Key" // used by propagator and EventToCarrier function to identify trace header type mockHTTPRequest struct { Headers map[string][]string Body string } func mockEventToCarrier(eventJSON []byte) propagation.TextMapCarrier{ var request mockHTTPRequest _ = json.unmarshal(eventJSON, &request) return propogation.HeaderCarrier{someHeaderKey: []string{request.Headers[someHeaderKey]}} } type mockPropagator struct{} // Extract - read from `someHeaderKey` // Inject // Fields func HandleRequest(ctx context.Context, request mockHTTPRequest) error { return fmt.Sprintf("Hello %s!", request.Body ), nil } func main() { exp, _ := stdouttrace.New() tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exp)) lambda.Start(otellambda.InstrumentHandler(HandleRequest, otellambda.WithTracerProvider(tp), otellambda.WithFlusher(tp), otellambda.WithEventToCarrier(mockEventToCarrier), otellambda.WithPropagator(mockPropagator{}))) } ``` ## Useful links - For more information on OpenTelemetry, visit: - For more about OpenTelemetry Go: - For help or feedback on this project, join us in [GitHub Discussions][discussions-url] ## License Apache 2.0 - See [LICENSE][license-url] for more information. [license-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE [license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat [goref-image]: https://pkg.go.dev/badge/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda.svg [goref-url]: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda [discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions [lambda-detector-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/detectors/aws/lambda config.go000066400000000000000000000107761443314701600361660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" import ( "context" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) // A Flusher dictates how the instrumentation will attempt to flush // unexported spans at the end of each Lambda innovation. This is // very important in asynchronous settings because the Lambda runtime // may enter a 'frozen' state any time after the invocation completes. // Should this freeze happen and spans are left unexported, there can be a // long delay before those spans are exported. type Flusher interface { ForceFlush(context.Context) error } type noopFlusher struct{} func (*noopFlusher) ForceFlush(context.Context) error { return nil } // Compile time check our noopFlusher implements Flusher. var _ Flusher = &noopFlusher{} // An EventToCarrier function defines how the instrumentation should // prepare a TextMapCarrier for the configured propagator to read from. This // extra step is necessary because Lambda does not have HTTP headers to read // from and instead stores the headers it was invoked with (including TraceID, etc.) // as part of the invocation event. If using the AWS XRay tracing then the // trace information is instead stored in the Lambda environment. type EventToCarrier func(eventJSON []byte) propagation.TextMapCarrier func emptyEventToCarrier([]byte) propagation.TextMapCarrier { return propagation.HeaderCarrier{} } // Compile time check our emptyEventToCarrier implements EventToCarrier. var _ EventToCarrier = emptyEventToCarrier // Option applies a configuration option. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } type config struct { // TracerProvider is the TracerProvider which will be used // to create instrumentation spans // The default value of TracerProvider the global otel TracerProvider // returned by otel.GetTracerProvider() TracerProvider trace.TracerProvider // Flusher is the mechanism used to flush any unexported spans // each Lambda Invocation to avoid spans being unexported for long // when periods of time if Lambda freezes the execution environment // The default value of Flusher is a noop Flusher, using this // default can result in long data delays in asynchronous settings Flusher Flusher // EventToCarrier is the mechanism used to retrieve the TraceID // from the event or environment and generate a TextMapCarrier which // can then be used by a Propagator to extract the TraceID into our context // The default value of eventToCarrier is emptyEventToCarrier which returns // an empty HeaderCarrier, using this default will cause new spans to be part // of a new Trace and have no parent past our Lambda instrumentation span EventToCarrier EventToCarrier // Propagator is the Propagator which will be used // to extract Trace info into the context // The default value of Propagator the global otel Propagator // returned by otel.GetTextMapPropagator() Propagator propagation.TextMapPropagator } // WithTracerProvider configures the TracerProvider used by the // instrumentation. // // By default, the global TracerProvider is used. func WithTracerProvider(tracerProvider trace.TracerProvider) Option { return optionFunc(func(c *config) { c.TracerProvider = tracerProvider }) } // WithFlusher sets the used flusher. func WithFlusher(flusher Flusher) Option { return optionFunc(func(c *config) { c.Flusher = flusher }) } // WithEventToCarrier sets the used EventToCarrier. func WithEventToCarrier(eventToCarrier EventToCarrier) Option { return optionFunc(func(c *config) { c.EventToCarrier = eventToCarrier }) } // WithPropagator configures the propagator used by the instrumentation. // // By default, the global TextMapPropagator will be used. func WithPropagator(propagator propagation.TextMapPropagator) Option { return optionFunc(func(c *config) { c.Propagator = propagator }) } doc.go000066400000000000000000000021711443314701600354540ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otellambda instruments the github.com/aws/aws-lambda-go package. // // Two wrappers are provided which can be used to instrument Lambda, // one for each Lambda entrypoint. Their usages are shown below. // // lambda.Start() entrypoint: lambda.Start(otellambda.InstrumentHandler()) // lambda.StartHandler() entrypoint: lambda.StartHandler(otellambda.WrapHandler()) package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" example/000077500000000000000000000000001443314701600360125ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambdaDockerfile000066400000000000000000000017401443314701600400060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20 AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/aws/aws-lambda-go/otellambda/example RUN apt-get update FROM base AS aws-lambda # install other package(s) in base RUN apt-get install zip unzip RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \ && unzip awscliv2.zip \ && ./aws/install RUN apt-get -y install jq CMD ["./build.sh"] README.md000066400000000000000000000025511443314701600372740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example# aws/aws-lambda-go instrumentation example A simple example to demonstrate the AWS Lambda for Go instrumentation. In this example, container `aws-lambda-client` initializes an S3 client and an HTTP client and runs 2 basic operations: `listS3Buckets` and `GET`. These instructions assume you have [docker-compose](https://docs.docker.com/compose/) installed and setup, and [AWS credential](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) configured. 1. From within the `example` directory, bring up the project by running: ```sh docker-compose up --detach ``` 2. The instrumentation works with a `stdout` exporter. The example pulls this output from AWS and outputs back to stdout. To inspect the output (following build output), you can run: ```sh docker-compose logs ``` 3. After inspecting the client logs, the example can be cleaned up by running: ```sh docker-compose down ``` Note: Because the example runs on AWS Lambda, a handful of resources are created in AWS by the example. The example will automatically destroy any resources it makes; however, if you terminate the container before it completes you may have leftover resources in AWS. Should you terminate the container early, run the below command to ensure all AWS resources are cleaned up: ```sh ./manualAWSCleanup.sh ```assumeRolePolicyDocument.json000066400000000000000000000002631443314701600437040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }build.sh000077500000000000000000000114301443314701600374470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example#!/bin/sh # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # constants LAMBDA_FUNCTION_NAME=SampleLambdaGo ROLE_NAME="$LAMBDA_FUNCTION_NAME"Role POLICY_NAME="$LAMBDA_FUNCTION_NAME"Policy LOG_GROUP_NAME=/aws/lambda/"$LAMBDA_FUNCTION_NAME" AWS_ACCT_ID=$(aws sts get-caller-identity | jq '.Account | tonumber') MAX_CREATE_TRIES=5 MAX_GET_LOG_STREAM_TRIES=10 # build go executable echo "1/6 Building go executable" GOOS=linux GOARCH=amd64 go build -o ./build/bootstrap . > /dev/null cd build || exit zip bootstrap.zip bootstrap > /dev/null # create AWS resources echo "2/6 Creating necessary resources in AWS" aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://../assumeRolePolicyDocument.json > /dev/null aws iam create-policy --policy-name "$POLICY_NAME" --policy-document file://../policyForRoleDocument.json > /dev/null aws iam attach-role-policy --role-name "$ROLE_NAME" --policy-arn arn:aws:iam::"$AWS_ACCT_ID":policy/"$POLICY_NAME" > /dev/null aws logs create-log-group --log-group-name "$LOG_GROUP_NAME" > /dev/null # race condition exists such that a role can be created and validated # via IAM, yet still cannot be assumed by Lambda, we will retry up to # MAX_CREATE_TRIES times to create the function TIMEOUT="$MAX_CREATE_TRIES" CREATE_FUNCTION_SUCCESS=$(aws lambda create-function --function-name "$LAMBDA_FUNCTION_NAME" --runtime provided.al2 --handler bootstrap --zip-file fileb://bootstrap.zip --role arn:aws:iam::"$AWS_ACCT_ID":role/"$ROLE_NAME" --timeout 5 --tracing-config Mode=Active > /dev/null || echo "false") while [ "$CREATE_FUNCTION_SUCCESS" = "false" ] && [ "$TIMEOUT" -ne 1 ] ; do echo " Retrying create-function, role likely not ready for use..." sleep 1 TIMEOUT=$((TIMEOUT - 1)) CREATE_FUNCTION_SUCCESS=$(aws lambda create-function --function-name "$LAMBDA_FUNCTION_NAME" --runtime provided.al2 --handler bootstrap --zip-file fileb://bootstrap.zip --role arn:aws:iam::"$AWS_ACCT_ID":role/"$ROLE_NAME" --timeout 5 --tracing-config Mode=Active > /dev/null || echo "false") done if [ "$TIMEOUT" -eq 1 ] ; then echo "Error: max retries reached when attempting to create Lambda Function" fi # invoke lambda echo "3/6 Invoking lambda" aws lambda invoke --function-name "$LAMBDA_FUNCTION_NAME" --payload "" resp.json # get logs from lambda (via cloudwatch) # logs sent from lambda to Cloudwatch and retrieved # from there because example logs are too long to # return directly from lambda invocation echo "4/6 Storing logs from AWS" # significant (3+ second) delay can occur between invoking Lambda and # the related log stream existing in Cloudwatch. We will retry to # retrieve the log stream up to MAX_GET_LOG_STREAM_TRIES TIMEOUT="$MAX_GET_LOG_STREAM_TRIES" LOG_STREAM_NAME=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --order-by LastEventTime --descending | jq --raw-output '.logStreams[0].logStreamName') while [ "$LOG_STREAM_NAME" = "null" ] && [ "$TIMEOUT" -ne 1 ] ; do echo " Waiting for log stream to be created..." sleep 1 TIMEOUT=$((TIMEOUT - 1)) LOG_STREAM_NAME=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --order-by LastEventTime --descending | jq --raw-output '.logStreams[0].logStreamName') done if [ "$TIMEOUT" -eq 1 ] ; then echo "Timed out waiting for log stream to be created" fi # minor (<1 second) delay can exist when adding logs to the # log stream such that only partial logs will be returned. # Will wait small amount of time to let logs fully populate sleep 2 aws logs get-log-events --log-group-name "$LOG_GROUP_NAME" --log-stream-name "$LOG_STREAM_NAME" | jq --join-output '.events[] | select(has("message")) | .message' | jq -R -r '. as $line | try fromjson catch $line' > lambdaLogs # destroy lambda resources echo "5/6 Destroying AWS resources" aws logs delete-log-stream --log-group-name "$LOG_GROUP_NAME" --log-stream-name "$LOG_STREAM_NAME" aws logs delete-log-group --log-group-name "$LOG_GROUP_NAME" aws lambda delete-function --function-name $LAMBDA_FUNCTION_NAME aws iam detach-role-policy --role-name "$ROLE_NAME" --policy-arn arn:aws:iam::"$AWS_ACCT_ID":policy/"$POLICY_NAME" aws iam delete-policy --policy-arn arn:aws:iam::"$AWS_ACCT_ID":policy/"$POLICY_NAME" aws iam delete-role --role-name "$ROLE_NAME" # display logs printf "6/6 Displaying logs from AWS:\n\n\n" cat lambdaLogs docker-compose.yml000066400000000000000000000015741443314701600414560ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: aws-lambda-client: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "./build.sh" volumes: - ~/.aws:/root/.aws networks: - example networks: example: go.mod000066400000000000000000000053001443314701600371160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/example go 1.18 replace ( go.opentelemetry.io/contrib/detectors/aws/lambda => ../../../../../../detectors/aws/lambda go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda => ../ go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws => ../../../aws-sdk-go-v2/otelaws go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../../../../../net/http/otelhttp ) require ( github.com/aws/aws-lambda-go v1.41.0 github.com/aws/aws-sdk-go-v2/config v1.18.25 github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 go.opentelemetry.io/contrib/detectors/aws/lambda v0.42.0 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda v0.42.0 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.42.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/aws/aws-sdk-go-v2 v1.18.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.24 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000170411443314701600371500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/examplegithub.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= github.com/aws/aws-sdk-go-v2/config v1.18.25 h1:JuYyZcnMPBiFqn87L2cRppo+rNwgah6YwD3VuyvaW6Q= github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= github.com/aws/aws-sdk-go-v2/credentials v1.13.24 h1:PjiYyls3QdCrzqUN35jMWtUK1vqVZ+zLfdOa/UPFDp0= github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 h1:AzwRi5OKKwo4QNqPf7TjeO+tK8AyOK3GVSwmRPo7/Cs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25/go.mod h1:SUbB4wcbSEyCvqBxv/O/IBf93RbEze7U7OnoTlpPB+g= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 h1:yb2o8oh3Y+Gg2g+wlzrWS3pB89+dHrXayT/d9cs8McU= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7/go.mod h1:1MNss6sqoIsFGisX92do/5doiUCBrN7EjhZCS/8DUjI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 h1:vGWm5vTpMr39tEZfQeDiDAMgk+5qsnvRny3FjLpnH5w= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28/go.mod h1:spfrICMD6wCAhjhzHuy6DOZZ+LAIY10UxhUmLzpJTTs= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 h1:QmyPCRZNMR1pFbiOi9kBZWZuKrKB9LD4cxltxQk4tNE= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27/go.mod h1:DfuVY36ixXnsG+uTqnoLWunXAKJ4qjccoFrXUPpj+hs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 h1:NbWkRxEEIRSCqxhsHQuMiTH7yo+JZW1gp8v3elSVMTQ= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2/go.mod h1:4tfW5l4IAB32VWCDEBxCRtR9T4BWy4I4kr1spr8NgZM= github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 h1:O+9nAy9Bb6bJFTpeNFtd9UfHbgxO1o4ZDAM9rQp5NsY= github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1/go.mod h1:J9kLNzEiHSeGMyN7238EjJmBpCniVzFda75Gxl/NqB8= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 h1:ikSvot5NdywduxtkOwOa2GJFzFuJq1ZjXsGjoIA82Ao= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0/go.mod h1:ujUjm+PrcKUeIiKu2PT7MWjcyY0D6YZRZF3fSswiO+0= github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY= github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 h1:2DQLAKDteoEDI8zpCzqBMaZlJuoE9iTYD0gFmXVax9E= github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= main.go000066400000000000000000000063601443314701600372720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "encoding/json" "io" "log" "net/http" "github.com/aws/aws-lambda-go/lambda" awsConfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func lambdaHandler(ctx context.Context) error { // init aws config cfg, err := awsConfig.LoadDefaultConfig(ctx) if err != nil { return err } // instrument all aws clients otelaws.AppendMiddlewares(&cfg.APIOptions) // S3 s3Client := s3.NewFromConfig(cfg) input := &s3.ListBucketsInput{} result, err := s3Client.ListBuckets(ctx, input) if err != nil { return err } log.Println("Buckets:") for _, bucket := range result.Buckets { log.Println(*bucket.Name + ": " + bucket.CreationDate.Format("2006-01-02 15:04:05 Monday")) } // HTTP client := &http.Client{ Transport: otelhttp.NewTransport( http.DefaultTransport, otelhttp.WithTracerProvider(otel.GetTracerProvider()), ), } req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/repos/open-telemetry/opentelemetry-go/releases/latest", nil) if err != nil { log.Printf("failed to create http request, %v\n", err) return err } res, err := client.Do(req) if err != nil { log.Printf("failed to do http request, %v\n", err) return err } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { log.Printf("failed to close http response body, %v\n", err) } }(res.Body) var data map[string]interface{} err = json.NewDecoder(res.Body).Decode(&data) if err != nil { log.Printf("failed to read http response body, %v\n", err) } log.Printf("Latest OTel Go Release is '%s'\n", data["name"]) return nil } func main() { ctx := context.Background() exp, err := stdouttrace.New() if err != nil { log.Printf("failed to initialize stdout exporter %v\n", err) return } detector := lambdadetector.NewResourceDetector() res, err := detector.Detect(ctx) if err != nil { log.Fatalf("failed to detect lambda resources: %v\n", err) return } tp := sdktrace.NewTracerProvider( sdktrace.WithSyncer(exp), sdktrace.WithResource(res), ) // Downstream spans use global tracer provider otel.SetTracerProvider(tp) lambda.Start(otellambda.InstrumentHandler(lambdaHandler, otellambda.WithTracerProvider(tp))) } manualAWSCleanup.sh000077500000000000000000000054471443314701600415230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example#!/bin/sh # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # constants LAMBDA_FUNCTION_NAME=SampleLambdaGo ROLE_NAME="$LAMBDA_FUNCTION_NAME"Role POLICY_NAME="$LAMBDA_FUNCTION_NAME"Policy LOG_GROUP_NAME=/aws/lambda/"$LAMBDA_FUNCTION_NAME" AWS_ACCT_ID=$(aws sts get-caller-identity | jq '.Account | tonumber') ERROR_LOG_FILE=manualAWSCleanupErrors.log # Clear log rm $ERROR_LOG_FILE 2> /dev/null # clear log group of all streams if aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" > /dev/null 2>> $ERROR_LOG_FILE ; then LOG_STREAM_NAME=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --order-by LastEventTime --descending | jq --raw-output '.logStreams[0].logStreamName') while [ "$LOG_STREAM_NAME" != "null" ] ; do aws logs delete-log-stream --log-group-name "$LOG_GROUP_NAME" --log-stream-name "$LOG_STREAM_NAME" 2>> $ERROR_LOG_FILE && echo "Deleted log stream $LOG_STREAM_NAME" LOG_STREAM_NAME=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --order-by LastEventTime --descending | jq --raw-output '.logStreams[0].logStreamName') done aws logs delete-log-group --log-group-name "$LOG_GROUP_NAME" && echo "Deleted log group $LOG_GROUP_NAME" else echo "Did not delete log group, likely already deleted" fi # destroy remaining lambda resources if they exist aws lambda delete-function --function-name "$LAMBDA_FUNCTION_NAME" 2>> $ERROR_LOG_FILE && echo "Deleted Lambda Function $LAMBDA_FUNCTION_NAME" || echo "Did not delete function, likely already deleted" aws iam detach-role-policy --role-name "$ROLE_NAME" --policy-arn arn:aws:iam::"$AWS_ACCT_ID":policy/"$POLICY_NAME" 2>> $ERROR_LOG_FILE && echo "Detached $POLICY_NAME from $ROLE_NAME" || echo "Did not detach policy from role, likely already detached" aws iam delete-policy --policy-arn arn:aws:iam::"$AWS_ACCT_ID":policy/"$POLICY_NAME" 2>> $ERROR_LOG_FILE && echo "Deleted IAM Policy POLICY_NAME" || echo "Did not delete IAM Policy, likely already deleted" aws iam delete-role --role-name "$ROLE_NAME" 2>> $ERROR_LOG_FILE && echo "Deleted IAM Role $ROLE_NAME" || echo "Did not delete IAM Role, likely already deleted" if [ -s $ERROR_LOG_FILE ] ; then echo 'Some resources failed to delete. Can ensure these errors were due to the resources existing by checking "'$ERROR_LOG_FILE'"' fipolicyForRoleDocument.json000066400000000000000000000005301443314701600431720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/example{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": "*" }, { "Sid": "", "Effect": "Allow", "Action": [ "logs:PutLogEvents", "logs:CreateLogStream", "logs:CreateLogGroup" ], "Resource": "*" } ] }go.mod000066400000000000000000000010451443314701600354650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambdamodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda go 1.19 require ( github.com/aws/aws-lambda-go v1.41.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000040471443314701600355170ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambdagithub.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lambda.go000066400000000000000000000065461443314701600361410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" import ( "context" "log" "os" "strings" "github.com/aws/aws-lambda-go/lambdacontext" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) const ( tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" ) var errorLogger = log.New(log.Writer(), "OTel Lambda Error: ", 0) type instrumentor struct { configuration config resAttrs []attribute.KeyValue tracer trace.Tracer } func newInstrumentor(opts ...Option) instrumentor { cfg := config{ TracerProvider: otel.GetTracerProvider(), Flusher: &noopFlusher{}, EventToCarrier: emptyEventToCarrier, Propagator: otel.GetTextMapPropagator(), } for _, opt := range opts { opt.apply(&cfg) } return instrumentor{configuration: cfg, tracer: cfg.TracerProvider.Tracer(tracerName, trace.WithInstrumentationVersion(Version())), resAttrs: []attribute.KeyValue{}} } // Logic to start OTel Tracing. func (i *instrumentor) tracingBegin(ctx context.Context, eventJSON []byte) (context.Context, trace.Span) { // Add trace id to context mc := i.configuration.EventToCarrier(eventJSON) ctx = i.configuration.Propagator.Extract(ctx, mc) var span trace.Span spanName := os.Getenv("AWS_LAMBDA_FUNCTION_NAME") var attributes []attribute.KeyValue lc, ok := lambdacontext.FromContext(ctx) if !ok { errorLogger.Println("failed to load lambda context from context, ensure tracing enabled in Lambda") } if lc != nil { ctxRequestID := lc.AwsRequestID attributes = append(attributes, semconv.FaaSExecution(ctxRequestID)) // Some resource attrs added as span attrs because lambda // resource detectors are created before a lambda // invocation and therefore lack lambdacontext. // Create these attrs upon first invocation if len(i.resAttrs) == 0 { ctxFunctionArn := lc.InvokedFunctionArn attributes = append(attributes, semconv.FaaSID(ctxFunctionArn)) arnParts := strings.Split(ctxFunctionArn, ":") if len(arnParts) >= 5 { attributes = append(attributes, semconv.CloudAccountID(arnParts[4])) } } attributes = append(attributes, i.resAttrs...) } ctx, span = i.tracer.Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attributes...)) return ctx, span } // Logic to wrap up OTel Tracing. func (i *instrumentor) tracingEnd(ctx context.Context, span trace.Span) { span.End() // force flush any tracing data since lambda may freeze err := i.configuration.Flusher.ForceFlush(ctx) if err != nil { errorLogger.Println("failed to force a flush, lambda may freeze before instrumentation exported: ", err) } } lambda_test.go000066400000000000000000000220131443314701600371630ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda import ( "context" "encoding/json" "errors" "fmt" "os" "reflect" "testing" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-lambda-go/lambda/messages" "github.com/aws/aws-lambda-go/lambdacontext" "github.com/stretchr/testify/assert" ) var ( mockLambdaContext = lambdacontext.LambdaContext{ AwsRequestID: "123", InvokedFunctionArn: "arn:partition:service:region:account-id:resource-type:resource-id", Identity: lambdacontext.CognitoIdentity{ CognitoIdentityID: "someId", CognitoIdentityPoolID: "somePoolId", }, ClientContext: lambdacontext.ClientContext{}, } mockContext = lambdacontext.NewContext(context.TODO(), &mockLambdaContext) ) type emptyHandler struct{} func (h emptyHandler) Invoke(_ context.Context, _ []byte) ([]byte, error) { return nil, nil } var _ lambda.Handler = emptyHandler{} func setEnvVars() { _ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction") _ = os.Setenv("AWS_REGION", "us-texas-1") _ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST") _ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc") _ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128") _ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1") } func TestLambdaHandlerSignatures(t *testing.T) { setEnvVars() emptyPayload := "" testCases := []struct { name string handler interface{} expected error args []reflect.Value }{ { name: "nil handler", expected: errors.New("handler is nil"), handler: nil, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "handler is not a function", expected: errors.New("handler kind struct is not func"), handler: struct{}{}, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "handler declares too many arguments", expected: errors.New("handlers may not take more than two arguments, but handler takes 3"), handler: func(n context.Context, x string, y string) error { return nil }, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "two argument handler does not have context as first argument", expected: errors.New("handler takes two arguments, but the first is not Context. got string"), handler: func(a string, x context.Context) error { return nil }, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "handler returns too many values", expected: errors.New("handler may not return more than two values"), handler: func() (error, error, error) { return nil, nil, nil }, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "handler returning two values does not declare error as the second return value", expected: errors.New("handler returns two values, but the second does not implement error"), handler: func() (error, string) { return nil, "hello" }, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "handler returning a single value does not implement error", expected: errors.New("handler returns a single value, but it does not implement error"), handler: func() string { return "hello" }, args: []reflect.Value{reflect.ValueOf(mockContext), reflect.ValueOf(emptyPayload)}, }, { name: "no args or return value should not result in error", expected: nil, handler: func() { }, args: []reflect.Value{reflect.ValueOf(mockContext)}, // reminder - customer takes no args but wrapped handler always takes context from lambda }, } for i, testCase := range testCases { testCase := testCase t.Run(fmt.Sprintf("testCase[%d] %s", i, testCase.name), func(t *testing.T) { lambdaHandler := InstrumentHandler(testCase.handler) handler := reflect.ValueOf(lambdaHandler) resp := handler.Call(testCase.args) assert.Equal(t, 2, len(resp)) assert.Equal(t, testCase.expected, resp[1].Interface()) }) } } type expected struct { val interface{} err error } func TestHandlerInvokes(t *testing.T) { setEnvVars() hello := func(s string) string { return fmt.Sprintf("Hello %s!", s) } testCases := []struct { name string input interface{} expected expected handler interface{} }{ { name: "string input and return without context", input: "Lambda", expected: expected{`"Hello Lambda!"`, nil}, handler: func(name string) (string, error) { return hello(name), nil }, }, { name: "string input and return with context", input: "Lambda", expected: expected{`"Hello Lambda!"`, nil}, handler: func(ctx context.Context, name string) (string, error) { return hello(name), nil }, }, { name: "no input with response event and simple error", input: nil, expected: expected{"", errors.New("bad stuff")}, handler: func() (interface{}, error) { return nil, errors.New("bad stuff") }, }, { name: "input with response event and simple error", input: "Lambda", expected: expected{"", errors.New("bad stuff")}, handler: func(e interface{}) (interface{}, error) { return nil, errors.New("bad stuff") }, }, { name: "input and context with response event and simple error", input: "Lambda", expected: expected{"", errors.New("bad stuff")}, handler: func(ctx context.Context, e interface{}) (interface{}, error) { return nil, errors.New("bad stuff") }, }, { name: "input with response event and complex error", input: "Lambda", expected: expected{"", messages.InvokeResponse_Error{Message: "message", Type: "type"}}, handler: func(e interface{}) (interface{}, error) { return nil, messages.InvokeResponse_Error{Message: "message", Type: "type"} }, }, { name: "basic input struct serialization", input: struct{ Custom int }{9001}, expected: expected{`9001`, nil}, handler: func(event struct{ Custom int }) (int, error) { return event.Custom, nil }, }, { name: "basic output struct serialization", input: 9001, expected: expected{`{"Number":9001}`, nil}, handler: func(event int) (struct{ Number int }, error) { return struct{ Number int }{event}, nil }, }, } // test invocation via a lambda handler for i, testCase := range testCases { testCase := testCase t.Run(fmt.Sprintf("lambdaHandlerTestCase[%d] %s", i, testCase.name), func(t *testing.T) { lambdaHandler := InstrumentHandler(testCase.handler) handler := reflect.ValueOf(lambdaHandler) handlerType := handler.Type() var args []reflect.Value args = append(args, reflect.ValueOf(mockContext)) if handlerType.NumIn() > 1 { args = append(args, reflect.ValueOf(testCase.input)) } response := handler.Call(args) assert.Equal(t, 2, len(response)) if testCase.expected.err != nil { assert.Equal(t, testCase.expected.err, response[handlerType.NumOut()-1].Interface()) } else { assert.Nil(t, response[handlerType.NumOut()-1].Interface()) responseValMarshalled, _ := json.Marshal(response[0].Interface()) assert.Equal(t, testCase.expected.val, string(responseValMarshalled)) } }) } // test invocation via a Handler for i, testCase := range testCases { testCase := testCase t.Run(fmt.Sprintf("handlerTestCase[%d] %s", i, testCase.name), func(t *testing.T) { handler := WrapHandler(lambda.NewHandler(testCase.handler)) inputPayload, _ := json.Marshal(testCase.input) response, err := handler.Invoke(mockContext, inputPayload) if testCase.expected.err != nil { assert.Equal(t, testCase.expected.err, err) } else { assert.NoError(t, err) assert.Equal(t, testCase.expected.val, string(response)) } }) } } func BenchmarkInstrumentHandler(b *testing.B) { setEnvVars() customerHandler := func(ctx context.Context, payload int) error { return nil } wrapped := InstrumentHandler(customerHandler) wrappedCallable := reflect.ValueOf(wrapped) ctx := reflect.ValueOf(mockContext) payload := reflect.ValueOf(0) args := []reflect.Value{ctx, payload} b.ResetTimer() for i := 0; i < b.N; i++ { wrappedCallable.Call(args) } } func BenchmarkWrapHandler(b *testing.B) { setEnvVars() wrapped := WrapHandler(emptyHandler{}) b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = wrapped.Invoke(mockContext, []byte{0}) } } test/000077500000000000000000000000001443314701600353365ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambdadoc.go000066400000000000000000000017041443314701600364340ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates AWS Lambda instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/test" go.mod000066400000000000000000000021301443314701600364400ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/test go 1.19 replace ( go.opentelemetry.io/contrib/detectors/aws/lambda => ../../../../../../detectors/aws/lambda go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda => ../ go.opentelemetry.io/contrib/propagators/aws => ../../../../../../propagators/aws ) require ( github.com/aws/aws-lambda-go v1.41.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/detectors/aws/lambda v0.42.0 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda v0.42.0 go.opentelemetry.io/contrib/propagators/aws v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000045571443314701600365040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/testgithub.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lambda_test.go000066400000000000000000000336471443314701600401610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "encoding/json" "fmt" "log" "os" "reflect" "strconv" "strings" "sync" "testing" "time" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-lambda-go/lambdacontext" "github.com/stretchr/testify/assert" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) var errorLogger = log.New(log.Writer(), "OTel Lambda Test Error: ", 0) type mockIDGenerator struct { sync.Mutex traceCount int spanCount int } func (m *mockIDGenerator) NewIDs(_ context.Context) (trace.TraceID, trace.SpanID) { m.Lock() defer m.Unlock() m.traceCount++ m.spanCount++ return [16]byte{byte(m.traceCount)}, [8]byte{byte(m.spanCount)} } func (m *mockIDGenerator) NewSpanID(_ context.Context, _ trace.TraceID) trace.SpanID { m.Lock() defer m.Unlock() m.spanCount++ return [8]byte{byte(m.spanCount)} } var _ sdktrace.IDGenerator = &mockIDGenerator{} type emptyHandler struct{} func (h emptyHandler) Invoke(_ context.Context, _ []byte) ([]byte, error) { return nil, nil } var _ lambda.Handler = emptyHandler{} func initMockTracerProvider() (*sdktrace.TracerProvider, *tracetest.InMemoryExporter) { ctx := context.Background() exp := tracetest.NewInMemoryExporter() detector := lambdadetector.NewResourceDetector() res, err := detector.Detect(ctx) if err != nil { errorLogger.Printf("failed to detect lambda resources: %v\n", err) return nil, nil } tp := sdktrace.NewTracerProvider( sdktrace.WithSyncer(exp), sdktrace.WithIDGenerator(&mockIDGenerator{}), sdktrace.WithResource(res), ) return tp, exp } func setEnvVars() { _ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction") _ = os.Setenv("AWS_REGION", "us-texas-1") _ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST") _ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc") _ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128") _ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1") } // Vars for Tracing and TracingWithFlusher Tests. var ( mockLambdaContext = lambdacontext.LambdaContext{ AwsRequestID: "123", InvokedFunctionArn: "arn:partition:service:region:account-id:resource-type:resource-id", Identity: lambdacontext.CognitoIdentity{ CognitoIdentityID: "someId", CognitoIdentityPoolID: "somePoolId", }, ClientContext: lambdacontext.ClientContext{}, } mockContext = xray.Propagator{}.Extract(lambdacontext.NewContext(context.TODO(), &mockLambdaContext), propagation.HeaderCarrier{ "X-Amzn-Trace-Id": []string{"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"}, }) expectedTraceID, _ = trace.TraceIDFromHex("5759e988bd862e3fe1be46a994272793") expectedSpanStub = tracetest.SpanStub{ Name: "testFunction", SpanContext: trace.NewSpanContext(trace.SpanContextConfig{ TraceID: expectedTraceID, SpanID: trace.SpanID{1}, TraceFlags: 1, TraceState: trace.TraceState{}, Remote: false, }), Parent: trace.SpanContextFromContext(mockContext), SpanKind: trace.SpanKindServer, StartTime: time.Time{}, EndTime: time.Time{}, Attributes: []attribute.KeyValue{attribute.String("faas.execution", "123"), attribute.String("faas.id", "arn:partition:service:region:account-id:resource-type:resource-id"), attribute.String("cloud.account.id", "account-id")}, Events: nil, Links: nil, Status: sdktrace.Status{}, DroppedAttributes: 0, DroppedEvents: 0, DroppedLinks: 0, ChildSpanCount: 0, Resource: resource.NewWithAttributes(semconv.SchemaURL, attribute.String("cloud.provider", "aws"), attribute.String("cloud.region", "us-texas-1"), attribute.String("faas.name", "testFunction"), attribute.String("faas.version", "$LATEST"), attribute.String("faas.instance", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"), attribute.Int("faas.max_memory", 128)), InstrumentationLibrary: instrumentation.Library{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.Version()}, } ) func assertStubEqualsIgnoreTime(t *testing.T, expected tracetest.SpanStub, actual tracetest.SpanStub) { assert.Equal(t, expected.Name, actual.Name) assert.Equal(t, expected.SpanContext, actual.SpanContext) assert.Equal(t, expected.Parent, actual.Parent) assert.Equal(t, expected.SpanKind, actual.SpanKind) assert.Equal(t, expected.Attributes, actual.Attributes) assert.Equal(t, expected.Events, actual.Events) assert.Equal(t, expected.Links, actual.Links) assert.Equal(t, expected.Status, actual.Status) assert.Equal(t, expected.DroppedAttributes, actual.DroppedAttributes) assert.Equal(t, expected.DroppedEvents, actual.DroppedEvents) assert.Equal(t, expected.DroppedLinks, actual.DroppedLinks) assert.Equal(t, expected.ChildSpanCount, actual.ChildSpanCount) assert.Equal(t, expected.Resource, actual.Resource) assert.Equal(t, expected.InstrumentationLibrary, actual.InstrumentationLibrary) } func TestInstrumentHandlerTracing(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() customerHandler := func() (string, error) { return "hello world", nil } // No flusher needed as SimpleSpanProcessor is synchronous wrapped := otellambda.InstrumentHandler(customerHandler, otellambda.WithTracerProvider(tp)) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockContext)}) assert.Len(t, resp, 2) assert.Equal(t, "hello world", resp[0].Interface()) assert.Nil(t, resp[1].Interface()) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, expectedSpanStub, stub) } func TestWrapHandlerTracing(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() // No flusher needed as SimpleSpanProcessor is synchronous wrapped := otellambda.WrapHandler(emptyHandler{}, otellambda.WithTracerProvider(tp)) _, err := wrapped.Invoke(mockContext, []byte{}) assert.NoError(t, err) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, expectedSpanStub, stub) } type mockFlusher struct { flushCount int } func (mf *mockFlusher) ForceFlush(context.Context) error { mf.flushCount++ return nil } var _ otellambda.Flusher = &mockFlusher{} func TestInstrumentHandlerTracingWithFlusher(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() customerHandler := func() (string, error) { return "hello world", nil } flusher := mockFlusher{} wrapped := otellambda.InstrumentHandler(customerHandler, otellambda.WithTracerProvider(tp), otellambda.WithFlusher(&flusher)) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockContext)}) assert.Len(t, resp, 2) assert.Equal(t, "hello world", resp[0].Interface()) assert.Nil(t, resp[1].Interface()) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, expectedSpanStub, stub) assert.Equal(t, 1, flusher.flushCount) } func TestWrapHandlerTracingWithFlusher(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() flusher := mockFlusher{} wrapped := otellambda.WrapHandler(emptyHandler{}, otellambda.WithTracerProvider(tp), otellambda.WithFlusher(&flusher)) _, err := wrapped.Invoke(mockContext, []byte{}) assert.NoError(t, err) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, expectedSpanStub, stub) assert.Equal(t, 1, flusher.flushCount) } const mockPropagatorKey = "Mockkey" type mockPropagator struct{} func (prop mockPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { // extract tracing information if header := carrier.Get(mockPropagatorKey); header != "" { scc := trace.SpanContextConfig{} splitHeaderVal := strings.Split(header, ":") var err error scc.TraceID, err = trace.TraceIDFromHex(splitHeaderVal[0]) if err != nil { errorLogger.Println("Failed to create trace id from hex: ", err) } scc.SpanID, err = trace.SpanIDFromHex(splitHeaderVal[1]) if err != nil { errorLogger.Println("Failed to create span id from hex: ", err) } isTraced, err := strconv.Atoi(splitHeaderVal[1]) if err != nil { errorLogger.Println("Failed to convert trace flag to int: ", err) } scc.TraceFlags = scc.TraceFlags.WithSampled(isTraced != 0) sc := trace.NewSpanContext(scc) return trace.ContextWithRemoteSpanContext(ctx, sc) } return ctx } func (prop mockPropagator) Inject(context.Context, propagation.TextMapCarrier) { // not needed other than to satisfy interface } func (prop mockPropagator) Fields() []string { // not needed other than to satisfy interface return []string{} } type mockRequest struct { Headers map[string]string } // Vars for mockPropagator Tests. var ( mockPropagatorTestsTraceIDHex = "12345678901234567890123456789012" mockPropagatorTestsSpanIDHex = "1234567890123456" mockPropagatorTestsSampled = "1" mockPropagatorTestsHeader = mockPropagatorTestsTraceIDHex + ":" + mockPropagatorTestsSpanIDHex + ":" + mockPropagatorTestsSampled mockPropagatorTestsEvent = mockRequest{Headers: map[string]string{mockPropagatorKey: mockPropagatorTestsHeader}} mockPropagatorTestsContext = mockPropagator{}.Extract(lambdacontext.NewContext(context.TODO(), &mockLambdaContext), propagation.HeaderCarrier{mockPropagatorKey: []string{mockPropagatorTestsHeader}}) mockPropagatorTestsExpectedTraceID, _ = trace.TraceIDFromHex(mockPropagatorTestsTraceIDHex) mockPropagatorTestsExpectedSpanStub = tracetest.SpanStub{ Name: "testFunction", SpanContext: trace.NewSpanContext(trace.SpanContextConfig{ TraceID: mockPropagatorTestsExpectedTraceID, SpanID: trace.SpanID{1}, TraceFlags: 1, TraceState: trace.TraceState{}, Remote: false, }), Parent: trace.SpanContextFromContext(mockPropagatorTestsContext), SpanKind: trace.SpanKindServer, StartTime: time.Time{}, EndTime: time.Time{}, Attributes: []attribute.KeyValue{attribute.String("faas.execution", "123"), attribute.String("faas.id", "arn:partition:service:region:account-id:resource-type:resource-id"), attribute.String("cloud.account.id", "account-id")}, Events: nil, Links: nil, Status: sdktrace.Status{}, DroppedAttributes: 0, DroppedEvents: 0, DroppedLinks: 0, ChildSpanCount: 0, Resource: resource.NewWithAttributes(semconv.SchemaURL, attribute.String("cloud.provider", "aws"), attribute.String("cloud.region", "us-texas-1"), attribute.String("faas.name", "testFunction"), attribute.String("faas.version", "$LATEST"), attribute.String("faas.instance", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"), attribute.Int("faas.max_memory", 128)), InstrumentationLibrary: instrumentation.Library{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.Version()}, } ) func mockRequestCarrier(eventJSON []byte) propagation.TextMapCarrier { var event mockRequest err := json.Unmarshal(eventJSON, &event) if err != nil { fmt.Println("event type: ", reflect.TypeOf(event)) panic("mockRequestCarrier only supports events of type mockRequest") } return propagation.HeaderCarrier{mockPropagatorKey: []string{event.Headers[mockPropagatorKey]}} } func TestInstrumentHandlerTracingWithMockPropagator(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() customerHandler := func(event mockRequest) (string, error) { return "hello world", nil } // No flusher needed as SimpleSpanProcessor is synchronous wrapped := otellambda.InstrumentHandler(customerHandler, otellambda.WithTracerProvider(tp), otellambda.WithPropagator(mockPropagator{}), otellambda.WithEventToCarrier(mockRequestCarrier)) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockPropagatorTestsContext), reflect.ValueOf(mockPropagatorTestsEvent)}) assert.Len(t, resp, 2) assert.Equal(t, "hello world", resp[0].Interface()) assert.Nil(t, resp[1].Interface()) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, mockPropagatorTestsExpectedSpanStub, stub) } func TestWrapHandlerTracingWithMockPropagator(t *testing.T) { setEnvVars() tp, memExporter := initMockTracerProvider() // No flusher needed as SimpleSpanProcessor is synchronous wrapped := otellambda.WrapHandler(emptyHandler{}, otellambda.WithTracerProvider(tp), otellambda.WithPropagator(mockPropagator{}), otellambda.WithEventToCarrier(mockRequestCarrier)) payload, _ := json.Marshal(mockPropagatorTestsEvent) _, err := wrapped.Invoke(mockPropagatorTestsContext, payload) assert.NoError(t, err) assert.Len(t, memExporter.GetSpans(), 1) stub := memExporter.GetSpans()[0] assertStubEqualsIgnoreTime(t, mockPropagatorTestsExpectedSpanStub, stub) } version.go000066400000000000000000000020611443314701600363720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" // Version is the current release version of the AWS Lambda instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } wrapHandler.go000066400000000000000000000033341443314701600371600ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" import ( "context" "github.com/aws/aws-lambda-go/lambda" ) // wrappedHandler is a struct which holds an instrumentor // as well as the user's original lambda.Handler and is // able to instrument invocations of the user's lambda.Handler. type wrappedHandler struct { instrumentor instrumentor handler lambda.Handler } // Compile time check our Handler implements lambda.Handler. var _ lambda.Handler = wrappedHandler{} // Invoke adds OTel span surrounding customer Handler invocation. func (h wrappedHandler) Invoke(ctx context.Context, payload []byte) ([]byte, error) { ctx, span := h.instrumentor.tracingBegin(ctx, payload) defer h.instrumentor.tracingEnd(ctx, span) response, err := h.handler.Invoke(ctx, payload) if err != nil { return nil, err } return response, nil } // WrapHandler Provides a Handler which wraps customer Handler with OTel Tracing. func WrapHandler(handler lambda.Handler, options ...Option) lambda.Handler { return wrappedHandler{instrumentor: newInstrumentor(options...), handler: handler} } wrapLambdaHandler.go000066400000000000000000000147021443314701600402620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otellambda // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" import ( "context" "encoding/json" "fmt" "reflect" ) // wrappedHandlerFunction is a struct which only holds an instrumentor and is // able to instrument invocations of the user's lambda handler function. type wrappedHandlerFunction struct { instrumentor instrumentor } func errorHandler(e error) func(context.Context, interface{}) (interface{}, error) { return func(context.Context, interface{}) (interface{}, error) { return nil, e } } // Ensure handler takes 0-2 values, with context // as its first value if two arguments exist. func validateArguments(handler reflect.Type) (bool, error) { handlerTakesContext := false if handler.NumIn() > 2 { return false, fmt.Errorf("handlers may not take more than two arguments, but handler takes %d", handler.NumIn()) } else if handler.NumIn() > 0 { contextType := reflect.TypeOf((*context.Context)(nil)).Elem() argumentType := handler.In(0) handlerTakesContext = argumentType.Implements(contextType) if handler.NumIn() > 1 && !handlerTakesContext { return false, fmt.Errorf("handler takes two arguments, but the first is not Context. got %s", argumentType.Kind()) } } return handlerTakesContext, nil } // Ensure handler returns 0-2 values, with an error // as its first value if any exist. func validateReturns(handler reflect.Type) error { errorType := reflect.TypeOf((*error)(nil)).Elem() switch n := handler.NumOut(); { case n > 2: return fmt.Errorf("handler may not return more than two values") case n == 2: if !handler.Out(1).Implements(errorType) { return fmt.Errorf("handler returns two values, but the second does not implement error") } case n == 1: if !handler.Out(0).Implements(errorType) { return fmt.Errorf("handler returns a single value, but it does not implement error") } } return nil } // Wraps and calls customer lambda handler then unpacks response as necessary. func (whf *wrappedHandlerFunction) wrapperInternals(ctx context.Context, handlerFunc interface{}, eventJSON []byte, event reflect.Value, takesContext bool) (interface{}, error) { wrappedLambdaHandler := reflect.ValueOf(whf.wrapper(handlerFunc)) argsWrapped := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(eventJSON), event, reflect.ValueOf(takesContext)} response := wrappedLambdaHandler.Call(argsWrapped)[0].Interface().([]reflect.Value) // convert return values into (interface{}, error) var err error if len(response) > 0 { if errVal, ok := response[len(response)-1].Interface().(error); ok { err = errVal } } var val interface{} if len(response) > 1 { val = response[0].Interface() } return val, err } // InstrumentHandler Provides a lambda handler which wraps customer lambda handler with OTel Tracing. func InstrumentHandler(handlerFunc interface{}, options ...Option) interface{} { whf := wrappedHandlerFunction{instrumentor: newInstrumentor(options...)} if handlerFunc == nil { return errorHandler(fmt.Errorf("handler is nil")) } handlerType := reflect.TypeOf(handlerFunc) if handlerType.Kind() != reflect.Func { return errorHandler(fmt.Errorf("handler kind %s is not %s", handlerType.Kind(), reflect.Func)) } takesContext, err := validateArguments(handlerType) if err != nil { return errorHandler(err) } if err := validateReturns(handlerType); err != nil { return errorHandler(err) } // note we will always take context to capture lambda context, // regardless of whether customer takes context if handlerType.NumIn() == 0 || handlerType.NumIn() == 1 && takesContext { return func(ctx context.Context) (interface{}, error) { var temp *interface{} event := reflect.ValueOf(temp) return whf.wrapperInternals(ctx, handlerFunc, []byte{}, event, takesContext) } } // customer either takes both context and payload or just payload return func(ctx context.Context, payload interface{}) (interface{}, error) { event := reflect.New(handlerType.In(handlerType.NumIn() - 1)) // lambda SDK normally unmarshalls to customer event type, however // with the wrapper the SDK unmarshalls to map[string]interface{} // due to our use of reflection. Therefore we must convert this map // to customer's desired event, we do so by simply re-marshaling then // unmarshalling to the desired event type. The remarshalledPayload // will also be used by users using custom propagators remarshalledPayload, err := json.Marshal(payload) if err != nil { return nil, err } if err := json.Unmarshal(remarshalledPayload, event.Interface()); err != nil { return nil, err } return whf.wrapperInternals(ctx, handlerFunc, remarshalledPayload, event.Elem(), takesContext) } } // Adds OTel span surrounding customer handler call. func (whf *wrappedHandlerFunction) wrapper(handlerFunc interface{}) func(ctx context.Context, eventJSON []byte, event interface{}, takesContext bool) []reflect.Value { return func(ctx context.Context, eventJSON []byte, event interface{}, takesContext bool) []reflect.Value { ctx, span := whf.instrumentor.tracingBegin(ctx, eventJSON) defer whf.instrumentor.tracingEnd(ctx, span) handler := reflect.ValueOf(handlerFunc) var args []reflect.Value if takesContext { args = append(args, reflect.ValueOf(ctx)) } if eventExists(event) { args = append(args, reflect.ValueOf(event)) } response := handler.Call(args) return response } } // Determine if an interface{} is nil or the // if the reflect.Value of the event is nil. func eventExists(event interface{}) bool { if event == nil { return false } // reflect.Value.isNil() can only be called on // Values of certain Kinds. Unsupported Kinds // will panic rather than return false switch reflect.TypeOf(event).Kind() { case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: return !reflect.ValueOf(event).IsNil() } return true } xrayconfig/000077500000000000000000000000001443314701600365305ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambdaREADME.md000066400000000000000000000075721443314701600400220ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig# Recommended Configurations for OpenTelemetry AWS Lambda Instrumentation with AWS X-Ray [![Go Reference][goref-image]][goref-url] [![Apache License][license-image]][license-url] This module provides recommended configuration options for [`AWS Lambda Instrumentation`](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/aws/aws-lambda-go/otellambda) when using [AWS X-Ray](https://aws.amazon.com/xray/). By using this configuration, trace context will automatically be extracted from incoming requests with the `X-Amzn-Trace-Id` header if present. Trace context will also always be injected using the `X-Amzn-Trace-Id` format into downstream requests from the Lambda function. ## Installation ```bash go get -u go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig ``` ## Usage Create a sample Lambda Go application instrumented by the `otellambda` package such as below. ```go package main import ( "context" "fmt" "github.com/aws/aws-lambda-go/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" ) type MyEvent struct { Name string `json:"name"` } func HandleRequest(ctx context.Context, name MyEvent) (string, error) { return fmt.Sprintf("Hello %s!", name.Name ), nil } func main() { lambda.Start(otellambda.InstrumentHandler(HandleRequest)) } ``` Now configure the instrumentation with the provided options to export traces to AWS X-Ray via [the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) running as a Lambda Extension. Instructions for running the OTel Collector as a Lambda Extension can be found in the [AWS OpenTelemetry Documentation](https://aws-otel.github.io/docs/getting-started/lambda). ```go // Add import import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" // add options to InstrumentHandler call func main() { lambda.Start(otellambda.InstrumentHandler(HandleRequest, xrayconfig.WithRecommendedOptions()...)) } ``` ## Recommended AWS Lambda Instrumentation Options | Instrumentation Option | Recommended Value | Exported As | | --- | --- | --- | | `WithTracerProvider` | An `sdktrace.TracerProvider` configured to export in batches to an OTel Collector running locally in Lambda | Not individually exported. Can only be used via `WithRecommendedOptions()` | `WithFlusher` | An `otellambda.Flusher` which yields before calling ForceFlush on the configured `sdktrace.TracerProvider`. Yielding mitigates data delays caused by asynchronous nature of batching TracerProvider when in Lambda | Not individually exported. Can only be used via `WithRecommendedOptions()` | `WithEventToCarrier` | Function which reads X-Ray TraceID from Lambda environment and inserts it into a `propagtation.TextMapCarrier` | Individually exported as `WithEventToCarrier()`, also included in `WithRecommendedOptions()` | `WithPropagator` | An `xray.propagator` | Individually exported as `WithPropagator()`, also included in `WithRecommendedOptions()` ## Useful links - For more information on OpenTelemetry, visit: - For more about OpenTelemetry Go: - For help or feedback on this project, join us in [GitHub Discussions][discussions-url] ## License Apache 2.0 - See [LICENSE][license-url] for more information. [license-url]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/LICENSE [license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat [goref-image]: https://pkg.go.dev/badge/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig.svg [goref-url]: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig [discussions-url]: https://github.com/open-telemetry/opentelemetry-go/discussions collector_test.go000066400000000000000000000056121443314701600421100ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xrayconfig // Pared down version of go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlptracetest/collector.go // for end to end testing import ( "sort" collectortracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" commonpb "go.opentelemetry.io/proto/otlp/common/v1" resourcepb "go.opentelemetry.io/proto/otlp/resource/v1" tracepb "go.opentelemetry.io/proto/otlp/trace/v1" ) // SpansStorage stores the spans. Mock collectors can use it to // store spans they have received. type SpansStorage struct { rsm map[string]*tracepb.ResourceSpans spanCount int } // NewSpansStorage creates a new spans storage. func NewSpansStorage() SpansStorage { return SpansStorage{ rsm: make(map[string]*tracepb.ResourceSpans), } } // AddSpans adds spans to the spans storage. func (s *SpansStorage) AddSpans(request *collectortracepb.ExportTraceServiceRequest) { for _, rs := range request.GetResourceSpans() { rstr := resourceString(rs.Resource) if existingRs, ok := s.rsm[rstr]; !ok { s.rsm[rstr] = rs // TODO (rghetia): Add support for library Info. if len(rs.ScopeSpans) == 0 { rs.ScopeSpans = []*tracepb.ScopeSpans{ { Spans: []*tracepb.Span{}, }, } } s.spanCount += len(rs.ScopeSpans[0].Spans) } else { if len(rs.ScopeSpans) > 0 { newSpans := rs.ScopeSpans[0].GetSpans() existingRs.ScopeSpans[0].Spans = append(existingRs.ScopeSpans[0].Spans, newSpans...) s.spanCount += len(newSpans) } } } } // GetSpans returns the stored spans. func (s *SpansStorage) GetSpans() []*tracepb.Span { spans := make([]*tracepb.Span, 0, s.spanCount) for _, rs := range s.rsm { spans = append(spans, rs.ScopeSpans[0].Spans...) } return spans } // GetResourceSpans returns the stored resource spans. func (s *SpansStorage) GetResourceSpans() []*tracepb.ResourceSpans { rss := make([]*tracepb.ResourceSpans, 0, len(s.rsm)) for _, rs := range s.rsm { rss = append(rss, rs) } return rss } func resourceString(res *resourcepb.Resource) string { sAttrs := sortedAttributes(res.GetAttributes()) rstr := "" for _, attr := range sAttrs { rstr = rstr + attr.String() } return rstr } func sortedAttributes(attrs []*commonpb.KeyValue) []*commonpb.KeyValue { sort.Slice(attrs[:], func(i, j int) bool { return attrs[i].Key < attrs[j].Key }) return attrs } go.mod000066400000000000000000000033511443314701600376400ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfigmodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig go 1.19 replace ( go.opentelemetry.io/contrib/detectors/aws/lambda => ../../../../../../detectors/aws/lambda go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda => ../ go.opentelemetry.io/contrib/propagators/aws => ../../../../../../propagators/aws ) require ( github.com/aws/aws-lambda-go v1.41.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/detectors/aws/lambda v0.42.0 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda v0.42.0 go.opentelemetry.io/contrib/propagators/aws v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 go.opentelemetry.io/proto/otlp v0.19.0 google.golang.org/grpc v1.55.0 ) require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000001301371443314701600376700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfigcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= mock_collector_test.go000066400000000000000000000115761443314701600431270ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xrayconfig // Pared down version of go.opentelemtry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/mock_collector_test.go // for end to end testing import ( "context" "errors" "fmt" "net" "runtime" "sync" "testing" "time" "google.golang.org/grpc" "google.golang.org/grpc/metadata" collectortracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" tracepb "go.opentelemetry.io/proto/otlp/trace/v1" ) func makeMockCollector(t *testing.T, mockConfig *mockConfig) *mockCollector { return &mockCollector{ t: t, traceSvc: &mockTraceService{ storage: NewSpansStorage(), errors: mockConfig.errors, }, } } type mockTraceService struct { collectortracepb.UnimplementedTraceServiceServer errors []error requests int mu sync.RWMutex storage SpansStorage headers metadata.MD delay time.Duration } func (mts *mockTraceService) getResourceSpans() []*tracepb.ResourceSpans { mts.mu.RLock() defer mts.mu.RUnlock() return mts.storage.GetResourceSpans() } func (mts *mockTraceService) Export(ctx context.Context, exp *collectortracepb.ExportTraceServiceRequest) (*collectortracepb.ExportTraceServiceResponse, error) { if mts.delay > 0 { time.Sleep(mts.delay) } mts.mu.Lock() defer func() { mts.requests++ mts.mu.Unlock() }() reply := &collectortracepb.ExportTraceServiceResponse{} if mts.requests < len(mts.errors) { idx := mts.requests return reply, mts.errors[idx] } mts.headers, _ = metadata.FromIncomingContext(ctx) mts.storage.AddSpans(exp) return reply, nil } type mockCollector struct { t *testing.T traceSvc *mockTraceService endpoint string ln *listener stopFunc func() stopOnce sync.Once } type mockConfig struct { errors []error endpoint string } var _ collectortracepb.TraceServiceServer = (*mockTraceService)(nil) var errAlreadyStopped = fmt.Errorf("already stopped") func (mc *mockCollector) stop() error { var err = errAlreadyStopped mc.stopOnce.Do(func() { err = nil if mc.stopFunc != nil { mc.stopFunc() } }) // Give it sometime to shutdown. <-time.After(160 * time.Millisecond) // Getting the lock ensures the traceSvc is done flushing. mc.traceSvc.mu.Lock() defer mc.traceSvc.mu.Unlock() return err } func (mc *mockCollector) Stop() error { return mc.stop() } func (mc *mockCollector) getResourceSpans() []*tracepb.ResourceSpans { return mc.traceSvc.getResourceSpans() } func (mc *mockCollector) GetResourceSpans() []*tracepb.ResourceSpans { return mc.getResourceSpans() } func runMockCollectorAtEndpoint(t *testing.T, endpoint string) *mockCollector { return runMockCollectorWithConfig(t, &mockConfig{endpoint: endpoint}) } func runMockCollectorWithConfig(t *testing.T, mockConfig *mockConfig) *mockCollector { ln, err := net.Listen("tcp", mockConfig.endpoint) if err != nil { t.Fatalf("Failed to get an endpoint: %v", err) } srv := grpc.NewServer() mc := makeMockCollector(t, mockConfig) collectortracepb.RegisterTraceServiceServer(srv, mc.traceSvc) mc.ln = newListener(ln) go func() { _ = srv.Serve((net.Listener)(mc.ln)) }() mc.endpoint = ln.Addr().String() // srv.Stop calls Close on mc.ln. mc.stopFunc = srv.Stop return mc } type listener struct { closeOnce sync.Once wrapped net.Listener C chan struct{} } func newListener(wrapped net.Listener) *listener { return &listener{ wrapped: wrapped, C: make(chan struct{}, 1), } } func (l *listener) Close() error { return l.wrapped.Close() } func (l *listener) Addr() net.Addr { return l.wrapped.Addr() } // Accept waits for and returns the next connection to the listener. It will // send a signal on l.C that a connection has been made before returning. func (l *listener) Accept() (net.Conn, error) { conn, err := l.wrapped.Accept() if err != nil { if errors.Is(err, net.ErrClosed) { // If the listener has been closed, do not allow callers of // WaitForConn to wait for a connection that will never come. l.closeOnce.Do(func() { close(l.C) }) } return conn, err } select { case l.C <- struct{}{}: default: // If C is full, assume nobody is listening and move on. } return conn, nil } // WaitForConn will wait indefintely for a connection to be estabilished with // the listener before returning. func (l *listener) WaitForConn() { for { select { case <-l.C: return default: runtime.Gosched() } } } xrayconfig.go000066400000000000000000000054251443314701600412360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xrayconfig // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig" import ( "context" "os" lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func xrayEventToCarrier([]byte) propagation.TextMapCarrier { xrayTraceID := os.Getenv("_X_AMZN_TRACE_ID") return propagation.HeaderCarrier{"X-Amzn-Trace-Id": []string{xrayTraceID}} } // NewTracerProvider returns a TracerProvider configured with an exporter, // ID generator, and lambda resource detector to send trace data to AWS X-Ray // via a Collector instance listening on localhost. func NewTracerProvider(ctx context.Context) (*sdktrace.TracerProvider, error) { exp, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) if err != nil { return nil, err } detector := lambdadetector.NewResourceDetector() resource, err := detector.Detect(ctx) if err != nil { return nil, err } return sdktrace.NewTracerProvider( sdktrace.WithBatcher(exp), sdktrace.WithIDGenerator(xray.NewIDGenerator()), sdktrace.WithResource(resource), ), nil } // WithEventToCarrier returns an otellambda.Option to enable // an otellambda.EventToCarrier function which reads the XRay trace // information from the environment and returns this information in // a propagation.HeaderCarrier. func WithEventToCarrier() otellambda.Option { return otellambda.WithEventToCarrier(xrayEventToCarrier) } // WithPropagator returns an otellambda.Option to enable the xray.Propagator. func WithPropagator() otellambda.Option { return otellambda.WithPropagator(xray.Propagator{}) } // WithRecommendedOptions returns a list of all otellambda.Option(s) // recommended for the otellambda package when using AWS XRay. func WithRecommendedOptions(tp *sdktrace.TracerProvider) []otellambda.Option { return []otellambda.Option{WithEventToCarrier(), WithPropagator(), otellambda.WithTracerProvider(tp), otellambda.WithFlusher(tp)} } xrayconfig_test.go000066400000000000000000000203331443314701600422700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xrayconfig import ( "context" "os" "reflect" "runtime" "testing" "time" "github.com/aws/aws-lambda-go/lambdacontext" "github.com/stretchr/testify/assert" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" v1common "go.opentelemetry.io/proto/otlp/common/v1" v1resource "go.opentelemetry.io/proto/otlp/resource/v1" v1trace "go.opentelemetry.io/proto/otlp/trace/v1" ) func TestEventToCarrier(t *testing.T) { os.Clearenv() _ = os.Setenv("_X_AMZN_TRACE_ID", "traceID") carrier := xrayEventToCarrier([]byte{}) assert.Equal(t, "traceID", carrier.Get("X-Amzn-Trace-Id")) } func TestEventToCarrierWithPropagator(t *testing.T) { os.Clearenv() _ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1") carrier := xrayEventToCarrier([]byte{}) ctx := xray.Propagator{}.Extract(context.Background(), carrier) expectedTraceID, _ := trace.TraceIDFromHex("5759e988bd862e3fe1be46a994272793") expectedSpanID, _ := trace.SpanIDFromHex("53995c3f42cd8ad8") expectedCtx := trace.ContextWithRemoteSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ TraceID: expectedTraceID, SpanID: expectedSpanID, TraceFlags: trace.FlagsSampled, TraceState: trace.TraceState{}, Remote: true, })) assert.Equal(t, expectedCtx, ctx) } func setEnvVars() { _ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction") _ = os.Setenv("AWS_REGION", "us-texas-1") _ = os.Setenv("AWS_LAMBDA_FUNCTION_VERSION", "$LATEST") _ = os.Setenv("AWS_LAMBDA_LOG_STREAM_NAME", "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc") _ = os.Setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128") _ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1") // fix issue: "The requested service provider could not be loaded or initialized." // Guess: The env for Windows in GitHub action is incomplete if runtime.GOOS == "windows" && os.Getenv("SYSTEMROOT") == "" { _ = os.Setenv("SYSTEMROOT", `C:\Windows`) } } // Vars for end to end testing. var ( mockLambdaContext = lambdacontext.LambdaContext{ AwsRequestID: "123", InvokedFunctionArn: "arn:partition:service:region:account-id:resource-type:resource-id", Identity: lambdacontext.CognitoIdentity{}, ClientContext: lambdacontext.ClientContext{}, } mockContext = xray.Propagator{}.Extract(lambdacontext.NewContext(context.Background(), &mockLambdaContext), propagation.HeaderCarrier{ "X-Amzn-Trace-Id": []string{"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"}, }) expectedSpans = v1trace.ScopeSpans{ Scope: &v1common.InstrumentationScope{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.Version()}, Spans: []*v1trace.Span{{ TraceId: []byte{0x57, 0x59, 0xe9, 0x88, 0xbd, 0x86, 0x2e, 0x3f, 0xe1, 0xbe, 0x46, 0xa9, 0x94, 0x27, 0x27, 0x93}, SpanId: nil, TraceState: "", ParentSpanId: []byte{0x53, 0x99, 0x5c, 0x3f, 0x42, 0xcd, 0x8a, 0xd8}, Name: "testFunction", Kind: v1trace.Span_SPAN_KIND_SERVER, StartTimeUnixNano: 0, EndTimeUnixNano: 0, Attributes: []*v1common.KeyValue{{Key: "faas.execution", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "123"}}}, {Key: "faas.id", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "arn:partition:service:region:account-id:resource-type:resource-id"}}}, {Key: "cloud.account.id", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "account-id"}}}}, DroppedAttributesCount: 0, Events: nil, DroppedEventsCount: 0, Links: nil, DroppedLinksCount: 0, Status: &v1trace.Status{Code: v1trace.Status_STATUS_CODE_UNSET}, }}, SchemaUrl: "", } expectedSpanResource = v1resource.Resource{ Attributes: []*v1common.KeyValue{{Key: "cloud.provider", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "aws"}}}, {Key: "cloud.region", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "us-texas-1"}}}, {Key: "faas.instance", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"}}}, {Key: "faas.max_memory", Value: &v1common.AnyValue{Value: &v1common.AnyValue_IntValue{IntValue: 128}}}, {Key: "faas.name", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "testFunction"}}}, {Key: "faas.version", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "$LATEST"}}}}, DroppedAttributesCount: 0, } expectedResourceSpans = v1trace.ResourceSpans{ Resource: &expectedSpanResource, ScopeSpans: []*v1trace.ScopeSpans{&expectedSpans}, SchemaUrl: "", } ) func assertResourceEquals(t *testing.T, expected *v1resource.Resource, actual *v1resource.Resource) { assert.Len(t, actual.Attributes, 6) assert.Equal(t, expected.Attributes[0].String(), actual.Attributes[0].String()) assert.Equal(t, expected.Attributes[1].String(), actual.Attributes[1].String()) assert.Equal(t, expected.Attributes[2].String(), actual.Attributes[2].String()) assert.Equal(t, expected.Attributes[3].String(), actual.Attributes[3].String()) assert.Equal(t, expected.Attributes[4].String(), actual.Attributes[4].String()) assert.Equal(t, expected.Attributes[5].String(), actual.Attributes[5].String()) assert.Equal(t, expected.DroppedAttributesCount, actual.DroppedAttributesCount) } // ignore timestamps and SpanID since time is obviously variable, // and SpanID is randomized when using xray IDGenerator. func assertSpanEqualsIgnoreTimeAndSpanID(t *testing.T, expected *v1trace.ResourceSpans, actual *v1trace.ResourceSpans) { assert.Equal(t, expected.ScopeSpans[0].Scope, actual.ScopeSpans[0].Scope) actualSpan := actual.ScopeSpans[0].Spans[0] expectedSpan := expected.ScopeSpans[0].Spans[0] assert.Equal(t, expectedSpan.Name, actualSpan.Name) assert.Equal(t, expectedSpan.ParentSpanId, actualSpan.ParentSpanId) assert.Equal(t, expectedSpan.Kind, actualSpan.Kind) assert.Equal(t, expectedSpan.Attributes, actualSpan.Attributes) assert.Equal(t, expectedSpan.Events, actualSpan.Events) assert.Equal(t, expectedSpan.Links, actualSpan.Links) assert.Equal(t, expectedSpan.Status, actualSpan.Status) assert.Equal(t, expectedSpan.DroppedAttributesCount, actualSpan.DroppedAttributesCount) assert.Equal(t, expectedSpan.DroppedEventsCount, actualSpan.DroppedEventsCount) assert.Equal(t, expectedSpan.DroppedLinksCount, actualSpan.DroppedLinksCount) assertResourceEquals(t, expected.Resource, actual.Resource) } func TestWrapEndToEnd(t *testing.T) { setEnvVars() ctx := context.Background() tp, err := NewTracerProvider(ctx) assert.NoError(t, err) customerHandler := func() (string, error) { return "hello world", nil } mockCollector := runMockCollectorAtEndpoint(t, ":4317") defer func() { _ = mockCollector.Stop() }() <-time.After(5 * time.Millisecond) wrapped := otellambda.InstrumentHandler(customerHandler, WithRecommendedOptions(tp)...) wrappedCallable := reflect.ValueOf(wrapped) resp := wrappedCallable.Call([]reflect.Value{reflect.ValueOf(mockContext)}) assert.Len(t, resp, 2) assert.Equal(t, "hello world", resp[0].Interface()) assert.Nil(t, resp[1].Interface()) resSpans := mockCollector.getResourceSpans() assert.Len(t, resSpans, 1) assertSpanEqualsIgnoreTimeAndSpanID(t, &expectedResourceSpans, resSpans[0]) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/000077500000000000000000000000001443314701600322205ustar00rootroot00000000000000otelaws/000077500000000000000000000000001443314701600336175ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2attributes.go000066400000000000000000000046711443314701600363440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" import ( "context" v2Middleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/service/sqs" "github.com/aws/smithy-go/middleware" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // AWS attributes. const ( RegionKey attribute.Key = "aws.region" RequestIDKey attribute.Key = "aws.request_id" AWSSystemVal string = "aws-api" ) var servicemap = map[string]AttributeSetter{ dynamodb.ServiceID: DynamoDBAttributeSetter, sqs.ServiceID: SQSAttributeSetter, } // SystemAttr return the AWS RPC system attribute. func SystemAttr() attribute.KeyValue { return semconv.RPCSystemKey.String(AWSSystemVal) } // OperationAttr returns the AWS operation attribute. func OperationAttr(operation string) attribute.KeyValue { return semconv.RPCMethod(operation) } // RegionAttr returns the AWS region attribute. func RegionAttr(region string) attribute.KeyValue { return RegionKey.String(region) } // ServiceAttr returns the AWS service attribute. func ServiceAttr(service string) attribute.KeyValue { return semconv.RPCService(service) } // RequestIDAttr returns the AWS request ID attribute. func RequestIDAttr(requestID string) attribute.KeyValue { return RequestIDKey.String(requestID) } // DefaultAttributeSetter checks to see if there are service specific attributes available to set for the AWS service. // If there are service specific attributes available then they will be included. func DefaultAttributeSetter(ctx context.Context, in middleware.InitializeInput) []attribute.KeyValue { serviceID := v2Middleware.GetServiceID(ctx) if fn, ok := servicemap[serviceID]; ok { return fn(ctx, in) } return []attribute.KeyValue{} } attributes_test.go000066400000000000000000000030171443314701600373740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func TestOperationAttr(t *testing.T) { operation := "test-operation" attr := OperationAttr(operation) assert.Equal(t, attribute.String("rpc.method", operation), attr) } func TestRegionAttr(t *testing.T) { region := "test-region" attr := RegionAttr(region) assert.Equal(t, attribute.String("aws.region", region), attr) } func TestServiceAttr(t *testing.T) { service := "test-service" attr := ServiceAttr(service) assert.Equal(t, semconv.RPCService(service), attr) } func TestRequestIDAttr(t *testing.T) { requestID := "test-request-id" attr := RequestIDAttr(requestID) assert.Equal(t, attribute.String("aws.request_id", requestID), attr) } func TestSystemAttribute(t *testing.T) { attr := SystemAttr() assert.Equal(t, semconv.RPCSystemKey.String("aws-api"), attr) } aws.go000066400000000000000000000132751443314701600347500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" import ( "context" "time" v2Middleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) const ( tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" ) type spanTimestampKey struct{} // AttributeSetter returns an array of KeyValue pairs, it can be used to set custom attributes. type AttributeSetter func(context.Context, middleware.InitializeInput) []attribute.KeyValue type otelMiddlewares struct { tracer trace.Tracer propagator propagation.TextMapPropagator attributeSetter []AttributeSetter } func (m otelMiddlewares) initializeMiddlewareBefore(stack *middleware.Stack) error { return stack.Initialize.Add(middleware.InitializeMiddlewareFunc("OTelInitializeMiddlewareBefore", func( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( out middleware.InitializeOutput, metadata middleware.Metadata, err error) { ctx = context.WithValue(ctx, spanTimestampKey{}, time.Now()) return next.HandleInitialize(ctx, in) }), middleware.Before) } func (m otelMiddlewares) initializeMiddlewareAfter(stack *middleware.Stack) error { return stack.Initialize.Add(middleware.InitializeMiddlewareFunc("OTelInitializeMiddlewareAfter", func( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( out middleware.InitializeOutput, metadata middleware.Metadata, err error) { serviceID := v2Middleware.GetServiceID(ctx) operation := v2Middleware.GetOperationName(ctx) region := v2Middleware.GetRegion(ctx) attributes := []attribute.KeyValue{ SystemAttr(), ServiceAttr(serviceID), RegionAttr(region), OperationAttr(operation), } for _, setter := range m.attributeSetter { attributes = append(attributes, setter(ctx, in)...) } ctx, span := m.tracer.Start(ctx, spanName(serviceID, operation), trace.WithTimestamp(ctx.Value(spanTimestampKey{}).(time.Time)), trace.WithSpanKind(trace.SpanKindClient), trace.WithAttributes(attributes...), ) defer span.End() out, metadata, err = next.HandleInitialize(ctx, in) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) } return out, metadata, err }), middleware.After) } func (m otelMiddlewares) deserializeMiddleware(stack *middleware.Stack) error { return stack.Deserialize.Add(middleware.DeserializeMiddlewareFunc("OTelDeserializeMiddleware", func( ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error) { out, metadata, err = next.HandleDeserialize(ctx, in) resp, ok := out.RawResponse.(*smithyhttp.Response) if !ok { // No raw response to wrap with. return out, metadata, err } span := trace.SpanFromContext(ctx) span.SetAttributes(semconv.HTTPStatusCode(resp.StatusCode)) requestID, ok := v2Middleware.GetRequestIDMetadata(metadata) if ok { span.SetAttributes(RequestIDAttr(requestID)) } return out, metadata, err }), middleware.Before) } func (m otelMiddlewares) finalizeMiddleware(stack *middleware.Stack) error { return stack.Finalize.Add(middleware.FinalizeMiddlewareFunc("OTelFinalizeMiddleware", func( ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error) { // Propagate the Trace information by injecting it into the HTTP request. switch req := in.Request.(type) { case *smithyhttp.Request: m.propagator.Inject(ctx, propagation.HeaderCarrier(req.Header)) default: } return next.HandleFinalize(ctx, in) }), middleware.Before) } func spanName(serviceID, operation string) string { spanName := serviceID if operation != "" { spanName += "." + operation } return spanName } // AppendMiddlewares attaches OTel middlewares to the AWS Go SDK V2 for instrumentation. // OTel middlewares can be appended to either all aws clients or a specific operation. // Please see more details in https://aws.github.io/aws-sdk-go-v2/docs/middleware/ func AppendMiddlewares(apiOptions *[]func(*middleware.Stack) error, opts ...Option) { cfg := config{ TracerProvider: otel.GetTracerProvider(), TextMapPropagator: otel.GetTextMapPropagator(), } for _, opt := range opts { opt.apply(&cfg) } if cfg.AttributeSetter == nil { cfg.AttributeSetter = []AttributeSetter{DefaultAttributeSetter} } m := otelMiddlewares{tracer: cfg.TracerProvider.Tracer(tracerName, trace.WithInstrumentationVersion(Version())), propagator: cfg.TextMapPropagator, attributeSetter: cfg.AttributeSetter} *apiOptions = append(*apiOptions, m.initializeMiddlewareBefore, m.initializeMiddlewareAfter, m.finalizeMiddleware, m.deserializeMiddleware) } aws_test.go000066400000000000000000000050501443314701600357770ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws import ( "context" "net/http" "testing" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/propagation" ) type mockPropagator struct { injectKey string injectValue string } func (p mockPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { carrier.Set(p.injectKey, p.injectValue) } func (p mockPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { return context.TODO() } func (p mockPropagator) Fields() []string { return []string{} } func Test_otelMiddlewares_finalizeMiddleware(t *testing.T) { stack := middleware.Stack{ Finalize: middleware.NewFinalizeStep(), } propagator := mockPropagator{ injectKey: "mock-key", injectValue: "mock-value", } m := otelMiddlewares{ propagator: propagator, } err := m.finalizeMiddleware(&stack) require.NoError(t, err) input := &smithyhttp.Request{ Request: &http.Request{ Header: http.Header{}, }, } next := middleware.HandlerFunc(func(ctx context.Context, input interface{}) (output interface{}, metadata middleware.Metadata, err error) { return nil, middleware.Metadata{}, nil }) _, _, _ = stack.Finalize.HandleMiddleware(context.Background(), input, next) // Assert header has been updated with injected values key := http.CanonicalHeaderKey(propagator.injectKey) value := propagator.injectValue assert.Contains(t, input.Header, key) assert.Contains(t, input.Header[key], value) } func Test_Span_name(t *testing.T) { serviceID1 := "" serviceID2 := "ServiceID" operation1 := "" operation2 := "Operation" assert.Equal(t, spanName(serviceID1, operation1), "") assert.Equal(t, spanName(serviceID1, operation2), "."+operation2) assert.Equal(t, spanName(serviceID2, operation1), serviceID2) assert.Equal(t, spanName(serviceID2, operation2), serviceID2+"."+operation2) } config.go000077500000000000000000000043721443314701600354240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" import ( "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) type config struct { TracerProvider trace.TracerProvider TextMapPropagator propagation.TextMapPropagator AttributeSetter []AttributeSetter } // Option applies an option value. type Option interface { apply(*config) } // optionFunc provides a convenience wrapper for simple Options // that can be represented as functions. type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global TracerProvider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithTextMapPropagator specifies a Text Map Propagator to use when propagating context. // If none is specified, the global TextMapPropagator is used. func WithTextMapPropagator(propagator propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagator != nil { cfg.TextMapPropagator = propagator } }) } // WithAttributeSetter specifies an attribute setter function for setting service specific attributes. // If none is specified, the service will be determined by the DefaultAttributeSetter function and the corresponding attributes will be included. func WithAttributeSetter(attributesetters ...AttributeSetter) Option { return optionFunc(func(cfg *config) { cfg.AttributeSetter = append(cfg.AttributeSetter, attributesetters...) }) } config_test.go000066400000000000000000000016461443314701600364610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" ) func TestWithTextMapPropagator(t *testing.T) { cfg := config{} propagator := otel.GetTextMapPropagator() option := WithTextMapPropagator(propagator) option.apply(&cfg) assert.Equal(t, cfg.TextMapPropagator, propagator) } dynamodbattributes.go000066400000000000000000000160441443314701600400570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" import ( "context" "encoding/json" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/smithy-go/middleware" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // DynamoDBAttributeSetter sets DynamoDB specific attributes depending on the DynamoDB operation being performed. func DynamoDBAttributeSetter(ctx context.Context, in middleware.InitializeInput) []attribute.KeyValue { dynamodbAttributes := []attribute.KeyValue{semconv.DBSystemDynamoDB} switch v := in.Parameters.(type) { case *dynamodb.GetItemInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) if v.ConsistentRead != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBConsistentRead(*v.ConsistentRead)) } if v.ProjectionExpression != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProjection(*v.ProjectionExpression)) } case *dynamodb.BatchGetItemInput: var tableNames []string for k := range v.RequestItems { tableNames = append(tableNames, k) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(tableNames...)) case *dynamodb.BatchWriteItemInput: var tableNames []string for k := range v.RequestItems { tableNames = append(tableNames, k) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(tableNames...)) case *dynamodb.CreateTableInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) if v.GlobalSecondaryIndexes != nil { var idx []string for _, gsi := range v.GlobalSecondaryIndexes { i, _ := json.Marshal(gsi) idx = append(idx, string(i)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBGlobalSecondaryIndexes(idx...)) } if v.LocalSecondaryIndexes != nil { var idx []string for _, lsi := range v.LocalSecondaryIndexes { i, _ := json.Marshal(lsi) idx = append(idx, string(i)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBLocalSecondaryIndexes(idx...)) } if v.ProvisionedThroughput != nil { read := float64(*v.ProvisionedThroughput.ReadCapacityUnits) dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProvisionedReadCapacity(read)) write := float64(*v.ProvisionedThroughput.WriteCapacityUnits) dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProvisionedWriteCapacity(write)) } case *dynamodb.DeleteItemInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) case *dynamodb.DeleteTableInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) case *dynamodb.DescribeTableInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) case *dynamodb.ListTablesInput: if v.ExclusiveStartTableName != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBExclusiveStartTable(*v.ExclusiveStartTableName)) } if v.Limit != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBLimit(int(*v.Limit))) } case *dynamodb.PutItemInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) case *dynamodb.QueryInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) if v.ConsistentRead != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBConsistentRead(*v.ConsistentRead)) } if v.IndexName != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBIndexName(*v.IndexName)) } if v.Limit != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBLimit(int(*v.Limit))) } if v.ScanIndexForward != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBScanForward(*v.ScanIndexForward)) } if v.ProjectionExpression != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProjection(*v.ProjectionExpression)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBSelect(string(v.Select))) case *dynamodb.ScanInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) if v.ConsistentRead != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBConsistentRead(*v.ConsistentRead)) } if v.IndexName != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBIndexName(*v.IndexName)) } if v.Limit != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBLimit(int(*v.Limit))) } if v.ProjectionExpression != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProjection(*v.ProjectionExpression)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBSelect(string(v.Select))) if v.Segment != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBSegment(int(*v.Segment))) } if v.TotalSegments != nil { dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTotalSegments(int(*v.TotalSegments))) } case *dynamodb.UpdateItemInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) case *dynamodb.UpdateTableInput: dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBTableNames(*v.TableName)) if v.AttributeDefinitions != nil { var def []string for _, ad := range v.AttributeDefinitions { d, _ := json.Marshal(ad) def = append(def, string(d)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBAttributeDefinitions(def...)) } if v.GlobalSecondaryIndexUpdates != nil { var idx []string for _, gsiu := range v.GlobalSecondaryIndexUpdates { i, _ := json.Marshal(gsiu) idx = append(idx, string(i)) } dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBGlobalSecondaryIndexUpdates(idx...)) } if v.ProvisionedThroughput != nil { read := float64(*v.ProvisionedThroughput.ReadCapacityUnits) dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProvisionedReadCapacity(read)) write := float64(*v.ProvisionedThroughput.WriteCapacityUnits) dynamodbAttributes = append(dynamodbAttributes, semconv.AWSDynamoDBProvisionedWriteCapacity(write)) } } return dynamodbAttributes } dynamodbattributes_test.go000066400000000000000000000273471443314701600411260ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws import ( "context" "testing" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/dynamodb" dtypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/aws/smithy-go/middleware" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/attribute" ) func TestDynamodbTagsBatchGetItemInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.BatchGetItemInput{ RequestItems: map[string]dtypes.KeysAndAttributes{ "table1": { Keys: []map[string]dtypes.AttributeValue{ { "id": &dtypes.AttributeValueMemberS{Value: "123"}, }, }, }, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice("aws.dynamodb.table_names", []string{"table1"})) } func TestDynamodbTagsBatchWriteItemInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.BatchWriteItemInput{ RequestItems: map[string][]dtypes.WriteRequest{ "table1": { { DeleteRequest: &dtypes.DeleteRequest{ Key: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "123"}, }, }, }, { PutRequest: &dtypes.PutRequest{ Item: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "234"}, }, }, }, }, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice("aws.dynamodb.table_names", []string{"table1"})) } func TestDynamodbTagsCreateTableInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.CreateTableInput{ AttributeDefinitions: []dtypes.AttributeDefinition{ { AttributeName: aws.String("id"), AttributeType: dtypes.ScalarAttributeTypeS, }, }, KeySchema: []dtypes.KeySchemaElement{ { AttributeName: aws.String("id"), KeyType: dtypes.KeyTypeHash, }, }, TableName: aws.String("table1"), BillingMode: dtypes.BillingModePayPerRequest, ProvisionedThroughput: &dtypes.ProvisionedThroughput{ ReadCapacityUnits: aws.Int64(123), WriteCapacityUnits: aws.Int64(456), }, GlobalSecondaryIndexes: []dtypes.GlobalSecondaryIndex{ { IndexName: aws.String("index1"), KeySchema: []dtypes.KeySchemaElement{ { AttributeName: aws.String("attributename"), KeyType: dtypes.KeyTypeHash, }, }, Projection: &dtypes.Projection{ NonKeyAttributes: []string{"non-key-attributes"}, }, }, }, LocalSecondaryIndexes: []dtypes.LocalSecondaryIndex{ { IndexName: aws.String("index2"), KeySchema: []dtypes.KeySchemaElement{ { AttributeName: aws.String("attributename"), KeyType: dtypes.KeyTypeHash, }, }, }, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.global_secondary_indexes", []string{ `{"IndexName":"index1","KeySchema":[{"AttributeName":"attributename","KeyType":"HASH"}],"Projection":{"NonKeyAttributes":["non-key-attributes"],"ProjectionType":""},"ProvisionedThroughput":null}`, }, )) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.local_secondary_indexes", []string{ `{"IndexName":"index2","KeySchema":[{"AttributeName":"attributename","KeyType":"HASH"}],"Projection":null}`, }, )) assert.Contains(t, attributes, attribute.Float64("aws.dynamodb.provisioned_read_capacity", 123)) assert.Contains(t, attributes, attribute.Float64("aws.dynamodb.provisioned_write_capacity", 456)) } func TestDynamodbTagsDeleteItemInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.DeleteItemInput{ Key: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "123"}, }, TableName: aws.String("table1"), }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) } func TestDynamodbTagsDeleteTableInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.DeleteTableInput{ TableName: aws.String("table1"), }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) } func TestDynamodbTagsDescribeTableInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.DescribeTableInput{ TableName: aws.String("table1"), }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) } func TestDynamodbTagsListTablesInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.ListTablesInput{ ExclusiveStartTableName: aws.String("table1"), Limit: aws.Int32(10), }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.String("aws.dynamodb.exclusive_start_table", "table1")) assert.Contains(t, attributes, attribute.Int("aws.dynamodb.limit", 10)) } func TestDynamodbTagsPutItemInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.PutItemInput{ TableName: aws.String("table1"), Item: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "12346"}, "name": &dtypes.AttributeValueMemberS{Value: "John Doe"}, "email": &dtypes.AttributeValueMemberS{Value: "john@doe.io"}, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) } func TestDynamodbTagsQueryInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.QueryInput{ TableName: aws.String("table1"), IndexName: aws.String("index1"), ConsistentRead: aws.Bool(true), Limit: aws.Int32(10), ScanIndexForward: aws.Bool(true), ProjectionExpression: aws.String("projectionexpression"), Select: dtypes.SelectAllAttributes, KeyConditionExpression: aws.String("id = :hashKey and #date > :rangeKey"), ExpressionAttributeNames: map[string]string{ "#date": "date", }, ExpressionAttributeValues: map[string]dtypes.AttributeValue{ ":hashKey": &dtypes.AttributeValueMemberS{Value: "123"}, ":rangeKey": &dtypes.AttributeValueMemberN{Value: "20150101"}, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) assert.Contains(t, attributes, attribute.Bool("aws.dynamodb.consistent_read", true)) assert.Contains(t, attributes, attribute.String("aws.dynamodb.index_name", "index1")) assert.Contains(t, attributes, attribute.Int("aws.dynamodb.limit", 10)) assert.Contains(t, attributes, attribute.Bool("aws.dynamodb.scan_forward", true)) assert.Contains(t, attributes, attribute.String("aws.dynamodb.projection", "projectionexpression")) assert.Contains(t, attributes, attribute.String("aws.dynamodb.select", "ALL_ATTRIBUTES")) } func TestDynamodbTagsScanInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.ScanInput{ TableName: aws.String("my-table"), ConsistentRead: aws.Bool(true), IndexName: aws.String("index1"), Limit: aws.Int32(10), ProjectionExpression: aws.String("Artist, Genre"), Segment: aws.Int32(10), TotalSegments: aws.Int32(100), Select: dtypes.SelectAllAttributes, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"my-table"}, )) assert.Contains(t, attributes, attribute.Bool("aws.dynamodb.consistent_read", true)) assert.Contains(t, attributes, attribute.String("aws.dynamodb.index_name", "index1")) assert.Contains(t, attributes, attribute.Int("aws.dynamodb.limit", 10)) assert.Contains(t, attributes, attribute.String("aws.dynamodb.select", "ALL_ATTRIBUTES")) assert.Contains(t, attributes, attribute.Int("aws.dynamodb.total_segments", 100)) assert.Contains(t, attributes, attribute.Int("aws.dynamodb.segment", 10)) assert.Contains(t, attributes, attribute.String("aws.dynamodb.projection", "Artist, Genre")) } func TestDynamodbTagsUpdateItemInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.UpdateItemInput{ TableName: aws.String("my-table"), Key: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "123"}, }, UpdateExpression: aws.String("set firstName = :firstName"), ExpressionAttributeValues: map[string]dtypes.AttributeValue{ ":firstName": &dtypes.AttributeValueMemberS{Value: "John McNewname"}, }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"my-table"}, )) } func TestDynamodbTagsUpdateTableInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &dynamodb.UpdateTableInput{ TableName: aws.String("my-table"), AttributeDefinitions: []dtypes.AttributeDefinition{ { AttributeName: aws.String("id"), AttributeType: dtypes.ScalarAttributeTypeS, }, }, GlobalSecondaryIndexUpdates: []dtypes.GlobalSecondaryIndexUpdate{ { Create: &dtypes.CreateGlobalSecondaryIndexAction{ IndexName: aws.String("index1"), KeySchema: []dtypes.KeySchemaElement{ { AttributeName: aws.String("attribute"), KeyType: dtypes.KeyTypeHash, }, }, Projection: &dtypes.Projection{ NonKeyAttributes: []string{"attribute1", "attribute2"}, ProjectionType: dtypes.ProjectionTypeAll, }, }, }, }, ProvisionedThroughput: &dtypes.ProvisionedThroughput{ ReadCapacityUnits: aws.Int64(123), WriteCapacityUnits: aws.Int64(456), }, }, } attributes := DynamoDBAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.table_names", []string{"my-table"}, )) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.attribute_definitions", []string{`{"AttributeName":"id","AttributeType":"S"}`}, )) assert.Contains(t, attributes, attribute.StringSlice( "aws.dynamodb.global_secondary_index_updates", []string{ `{"Create":{"IndexName":"index1","KeySchema":[{"AttributeName":"attribute","KeyType":"HASH"}],"Projection":{"NonKeyAttributes":["attribute1","attribute2"],"ProjectionType":"ALL"},"ProvisionedThroughput":null},"Delete":null,"Update":null}`, }, )) assert.Contains(t, attributes, attribute.Float64("aws.dynamodb.provisioned_read_capacity", 123)) assert.Contains(t, attributes, attribute.Float64("aws.dynamodb.provisioned_write_capacity", 456)) } example/000077500000000000000000000000001443314701600352525ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelawsDockerfile000066400000000000000000000014061443314701600372450ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example FROM base AS aws-client RUN go install ./main.go CMD ["/go/bin/main"] README.md000066400000000000000000000015531443314701600365350ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example# aws/aws-sdk-go-v2 instrumentation example A simple example to demonstrate the AWS SDK V2 for Go instrumentation. In this example, container `aws-sdk-client` initializes a S3 client and a DynamoDB client and runs 2 basic operations: `listS3Buckets` and `listDynamodbTables`. These instructions assume you have [docker-compose](https://docs.docker.com/compose/) installed and setup, and [AWS credential](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) configured. 1. From within the `example` directory, bring up the project by running: ```sh docker-compose up --detach ``` 2. The instrumentation works with a `stdout` exporter. To inspect the output, you can run: ```sh docker-compose logs ``` 3. After inspecting the client logs, the example can be cleaned up by running: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000015731443314701600407150ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: aws-sdk-client: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/main" volumes: - ~/.aws:/root/.aws networks: - example networks: example: go.mod000066400000000000000000000040511443314701600363600ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws => ../ require ( github.com/aws/aws-sdk-go-v2 v1.18.0 github.com/aws/aws-sdk-go-v2/config v1.18.25 github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.24 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000163011443314701600364060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/examplegithub.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= github.com/aws/aws-sdk-go-v2/config v1.18.25 h1:JuYyZcnMPBiFqn87L2cRppo+rNwgah6YwD3VuyvaW6Q= github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= github.com/aws/aws-sdk-go-v2/credentials v1.13.24 h1:PjiYyls3QdCrzqUN35jMWtUK1vqVZ+zLfdOa/UPFDp0= github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 h1:AzwRi5OKKwo4QNqPf7TjeO+tK8AyOK3GVSwmRPo7/Cs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25/go.mod h1:SUbB4wcbSEyCvqBxv/O/IBf93RbEze7U7OnoTlpPB+g= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 h1:yb2o8oh3Y+Gg2g+wlzrWS3pB89+dHrXayT/d9cs8McU= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7/go.mod h1:1MNss6sqoIsFGisX92do/5doiUCBrN7EjhZCS/8DUjI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 h1:vGWm5vTpMr39tEZfQeDiDAMgk+5qsnvRny3FjLpnH5w= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28/go.mod h1:spfrICMD6wCAhjhzHuy6DOZZ+LAIY10UxhUmLzpJTTs= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 h1:QmyPCRZNMR1pFbiOi9kBZWZuKrKB9LD4cxltxQk4tNE= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27/go.mod h1:DfuVY36ixXnsG+uTqnoLWunXAKJ4qjccoFrXUPpj+hs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 h1:NbWkRxEEIRSCqxhsHQuMiTH7yo+JZW1gp8v3elSVMTQ= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2/go.mod h1:4tfW5l4IAB32VWCDEBxCRtR9T4BWy4I4kr1spr8NgZM= github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 h1:O+9nAy9Bb6bJFTpeNFtd9UfHbgxO1o4ZDAM9rQp5NsY= github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1/go.mod h1:J9kLNzEiHSeGMyN7238EjJmBpCniVzFda75Gxl/NqB8= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 h1:ikSvot5NdywduxtkOwOa2GJFzFuJq1ZjXsGjoIA82Ao= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0/go.mod h1:ujUjm+PrcKUeIiKu2PT7MWjcyY0D6YZRZF3fSswiO+0= github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY= github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 h1:2DQLAKDteoEDI8zpCzqBMaZlJuoE9iTYD0gFmXVax9E= github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= main.go000066400000000000000000000051171443314701600365310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "fmt" "github.com/aws/aws-sdk-go-v2/aws" awsConfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/service/s3" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) var tp *sdktrace.TracerProvider func initTracer() { var err error exp, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { fmt.Printf("failed to initialize stdout exporter %v\n", err) return } bsp := sdktrace.NewBatchSpanProcessor(exp) tp = sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(bsp), ) otel.SetTracerProvider(tp) } func main() { initTracer() // Create a named tracer with package path as its name. tracer := tp.Tracer("example/aws/main") ctx := context.Background() defer func() { _ = tp.Shutdown(ctx) }() var span trace.Span ctx, span = tracer.Start(ctx, "AWS Example") defer span.End() // init aws config cfg, err := awsConfig.LoadDefaultConfig(ctx) if err != nil { panic("configuration error, " + err.Error()) } // instrument all aws clients otelaws.AppendMiddlewares(&cfg.APIOptions) // S3 s3Client := s3.NewFromConfig(cfg) input := &s3.ListBucketsInput{} result, err := s3Client.ListBuckets(ctx, input) if err != nil { fmt.Printf("Got an error retrieving buckets, %v", err) return } fmt.Println("Buckets:") for _, bucket := range result.Buckets { fmt.Println(*bucket.Name + ": " + bucket.CreationDate.Format("2006-01-02 15:04:05 Monday")) } // DynamoDb dynamoDbClient := dynamodb.NewFromConfig(cfg) resp, err := dynamoDbClient.ListTables(ctx, &dynamodb.ListTablesInput{ Limit: aws.Int32(5), }) if err != nil { fmt.Printf("failed to list tables, %v", err) return } fmt.Println("Tables:") for _, tableName := range resp.TableNames { fmt.Println(tableName) } } go.mod000066400000000000000000000020331443314701600347230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelawsmodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws go 1.19 require ( github.com/aws/aws-sdk-go-v2 v1.18.0 github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 github.com/aws/smithy-go v1.13.5 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000104761443314701600347620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelawsgithub.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 h1:yb2o8oh3Y+Gg2g+wlzrWS3pB89+dHrXayT/d9cs8McU= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7/go.mod h1:1MNss6sqoIsFGisX92do/5doiUCBrN7EjhZCS/8DUjI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 h1:QmyPCRZNMR1pFbiOi9kBZWZuKrKB9LD4cxltxQk4tNE= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27/go.mod h1:DfuVY36ixXnsG+uTqnoLWunXAKJ4qjccoFrXUPpj+hs= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 h1:ikSvot5NdywduxtkOwOa2GJFzFuJq1ZjXsGjoIA82Ao= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0/go.mod h1:ujUjm+PrcKUeIiKu2PT7MWjcyY0D6YZRZF3fSswiO+0= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sqsattributes.go000066400000000000000000000051211443314701600370620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" import ( "context" "github.com/aws/aws-sdk-go-v2/service/sqs" "github.com/aws/smithy-go/middleware" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // SQSAttributeSetter sets SQS specific attributes depending on the SQS operation being performed. func SQSAttributeSetter(ctx context.Context, in middleware.InitializeInput) []attribute.KeyValue { sqsAttributes := []attribute.KeyValue{semconv.MessagingSystem("AmazonSQS")} key := semconv.NetPeerNameKey switch v := in.Parameters.(type) { case *sqs.DeleteMessageBatchInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.DeleteMessageInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.DeleteQueueInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.GetQueueAttributesInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.ListDeadLetterSourceQueuesInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.ListQueueTagsInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.PurgeQueueInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.ReceiveMessageInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.RemovePermissionInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.SendMessageBatchInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.SendMessageInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.SetQueueAttributesInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.TagQueueInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) case *sqs.UntagQueueInput: sqsAttributes = append(sqsAttributes, key.String(*v.QueueUrl)) } return sqsAttributes } sqsattributes_test.go000066400000000000000000000121331443314701600401220ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws import ( "context" "testing" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sqs" "github.com/aws/smithy-go/middleware" "github.com/stretchr/testify/assert" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func TestSQSDeleteMessageBatchInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.DeleteMessageBatchInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSDeleteMessageInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.DeleteMessageInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSDeleteQueueInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.DeleteQueueInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSGetQueueAttributesInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.GetQueueAttributesInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSListDeadLetterSourceQueuesInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.ListDeadLetterSourceQueuesInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSListQueueTagsInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.ListQueueTagsInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSPurgeQueueInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.PurgeQueueInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSReceiveMessageInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.ReceiveMessageInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSRemovePermissionInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.RemovePermissionInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSSendMessageBatchInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.SendMessageBatchInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSSendMessageInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.SendMessageInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSSetQueueAttributesInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.SetQueueAttributesInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSTagQueueInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.TagQueueInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } func TestSQSUntagQueueInput(t *testing.T) { input := middleware.InitializeInput{ Parameters: &sqs.UntagQueueInput{ QueueUrl: aws.String("test-queue-url"), }, } attributes := SQSAttributeSetter(context.TODO(), input) assert.Contains(t, attributes, semconv.NetPeerName("test-queue-url")) } test/000077500000000000000000000000001443314701600345765ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelawsaws_test.go000066400000000000000000000121761443314701600367650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "net/http" "net/http/httptest" "testing" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/route53" "github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestAppendMiddlewares(t *testing.T) { cases := map[string]struct { responseStatus int responseBody []byte expectedRegion string expectedError codes.Code expectedRequestID string expectedStatusCode int }{ "invalidChangeBatchError": { responseStatus: http.StatusInternalServerError, responseBody: []byte(` Tried to create resource record set duplicate.example.com. type A, but it already exists b25f48e8-84fd-11e6-80d9-574e0c4664cb `), expectedRegion: "us-east-1", expectedError: codes.Error, expectedRequestID: "b25f48e8-84fd-11e6-80d9-574e0c4664cb", expectedStatusCode: http.StatusInternalServerError, }, "standardRestXMLError": { responseStatus: http.StatusNotFound, responseBody: []byte(` Sender MalformedXML 1 validation error detected: Value null at 'route53#ChangeSet' failed to satisfy constraint: Member must not be null 1234567890A `), expectedRegion: "us-west-1", expectedError: codes.Error, expectedRequestID: "1234567890A", expectedStatusCode: http.StatusNotFound, }, "Success response": { responseStatus: http.StatusOK, responseBody: []byte(` mockComment mockID `), expectedRegion: "us-west-2", expectedStatusCode: http.StatusOK, }, } for name, c := range cases { srv := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(c.responseStatus) _, err := w.Write(c.responseBody) if err != nil { t.Fatal(err) } })) t.Run(name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) svc := route53.NewFromConfig(aws.Config{ Region: c.expectedRegion, EndpointResolverWithOptions: aws.EndpointResolverWithOptionsFunc( func(service, region string, _ ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: srv.URL, SigningName: "route53", }, nil }, ), Retryer: func() aws.Retryer { return aws.NopRetryer{} }, }) _, err := svc.ChangeResourceRecordSets(context.Background(), &route53.ChangeResourceRecordSetsInput{ ChangeBatch: &types.ChangeBatch{ Changes: []types.Change{}, Comment: aws.String("mock"), }, HostedZoneId: aws.String("zone"), }, func(options *route53.Options) { otelaws.AppendMiddlewares( &options.APIOptions, otelaws.WithTracerProvider(provider)) }) if c.expectedError == codes.Unset { assert.NoError(t, err) } else { assert.NotNil(t, err) } spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "Route 53.ChangeResourceRecordSets", span.Name()) assert.Equal(t, trace.SpanKindClient, span.SpanKind()) assert.Equal(t, c.expectedError, span.Status().Code) attrs := span.Attributes() assert.Contains(t, attrs, attribute.Int("http.status_code", c.expectedStatusCode)) if c.expectedRequestID != "" { assert.Contains(t, attrs, attribute.String("aws.request_id", c.expectedRequestID)) } assert.Contains(t, attrs, attribute.String("rpc.system", "aws-api")) assert.Contains(t, attrs, attribute.String("rpc.service", "Route 53")) assert.Contains(t, attrs, attribute.String("aws.region", c.expectedRegion)) assert.Contains(t, attrs, attribute.String("rpc.method", "ChangeResourceRecordSets")) }) srv.Close() } } doc.go000066400000000000000000000017031443314701600356730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelaws instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test" dynamodbattributes_test.go000066400000000000000000000152011443314701600420670ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "net/http" "net/http/httptest" "testing" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/dynamodb" dtypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/aws/smithy-go/middleware" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestDynamodbTags(t *testing.T) { cases := struct { responseStatus int expectedRegion string expectedStatusCode int expectedError codes.Code }{ responseStatus: http.StatusOK, expectedRegion: "us-west-2", expectedStatusCode: http.StatusOK, } server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(cases.responseStatus) })) defer server.Close() t.Run("dynamodb tags", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) svc := dynamodb.NewFromConfig(aws.Config{ Region: cases.expectedRegion, EndpointResolverWithOptions: aws.EndpointResolverWithOptionsFunc( func(service, region string, _ ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: server.URL, SigningName: "dynamodb", }, nil }, ), Retryer: func() aws.Retryer { return aws.NopRetryer{} }, }) _, err := svc.GetItem(context.Background(), &dynamodb.GetItemInput{ TableName: aws.String("table1"), ConsistentRead: aws.Bool(false), ProjectionExpression: aws.String("test"), Key: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "test"}, }, }, func(options *dynamodb.Options) { otelaws.AppendMiddlewares( &options.APIOptions, otelaws.WithAttributeSetter(otelaws.DynamoDBAttributeSetter), otelaws.WithTracerProvider(provider)) }) if cases.expectedError == codes.Unset { assert.NoError(t, err) } else { assert.NotNil(t, err) } spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "DynamoDB.GetItem", span.Name()) assert.Equal(t, trace.SpanKindClient, span.SpanKind()) attrs := span.Attributes() assert.Contains(t, attrs, attribute.Int("http.status_code", cases.expectedStatusCode)) assert.Contains(t, attrs, attribute.String("rpc.service", "DynamoDB")) assert.Contains(t, attrs, attribute.String("aws.region", cases.expectedRegion)) assert.Contains(t, attrs, attribute.String("rpc.method", "GetItem")) assert.Contains(t, attrs, attribute.String("rpc.system", "aws-api")) assert.Contains(t, attrs, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) assert.Contains(t, attrs, attribute.String("aws.dynamodb.projection", "test")) assert.Contains(t, attrs, attribute.Bool("aws.dynamodb.consistent_read", false)) }) } func TestDynamodbTagsCustomSetter(t *testing.T) { cases := struct { responseStatus int expectedRegion string expectedStatusCode int expectedError codes.Code }{ responseStatus: http.StatusOK, expectedRegion: "us-west-2", expectedStatusCode: http.StatusOK, } server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(cases.responseStatus) })) defer server.Close() t.Run("dynamodb tags", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) svc := dynamodb.NewFromConfig(aws.Config{ Region: cases.expectedRegion, EndpointResolverWithOptions: aws.EndpointResolverWithOptionsFunc( func(service, region string, _ ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: server.URL, SigningName: "dynamodb", }, nil }, ), Retryer: func() aws.Retryer { return aws.NopRetryer{} }, }) mycustomsetter := otelaws.AttributeSetter(func(context.Context, middleware.InitializeInput) []attribute.KeyValue { customAttributes := []attribute.KeyValue{ { Key: "customattribute2key", Value: attribute.StringValue("customattribute2value"), }, { Key: "customattribute1key", Value: attribute.StringValue("customattribute1value"), }, } return customAttributes }) _, err := svc.GetItem(context.Background(), &dynamodb.GetItemInput{ TableName: aws.String("table1"), ConsistentRead: aws.Bool(false), ProjectionExpression: aws.String("test"), Key: map[string]dtypes.AttributeValue{ "id": &dtypes.AttributeValueMemberS{Value: "test"}, }, }, func(options *dynamodb.Options) { otelaws.AppendMiddlewares( &options.APIOptions, otelaws.WithAttributeSetter(otelaws.DynamoDBAttributeSetter, mycustomsetter), otelaws.WithTracerProvider(provider)) }) if cases.expectedError == codes.Unset { assert.NoError(t, err) } else { assert.NotNil(t, err) } spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "DynamoDB.GetItem", span.Name()) assert.Equal(t, trace.SpanKindClient, span.SpanKind()) attrs := span.Attributes() assert.Contains(t, attrs, attribute.Int("http.status_code", cases.expectedStatusCode)) assert.Contains(t, attrs, attribute.String("rpc.service", "DynamoDB")) assert.Contains(t, attrs, attribute.String("aws.region", cases.expectedRegion)) assert.Contains(t, attrs, attribute.String("rpc.method", "GetItem")) assert.Contains(t, attrs, attribute.StringSlice( "aws.dynamodb.table_names", []string{"table1"}, )) assert.Contains(t, attrs, attribute.String("aws.dynamodb.projection", "test")) assert.Contains(t, attrs, attribute.Bool("aws.dynamodb.consistent_read", false)) assert.Contains(t, attrs, attribute.String("customattribute2key", "customattribute2value")) assert.Contains(t, attrs, attribute.String("customattribute1key", "customattribute1value")) }) } go.mod000066400000000000000000000025501443314701600357060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test go 1.19 require ( github.com/aws/aws-sdk-go-v2 v1.18.0 github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1 github.com/aws/smithy-go v1.13.5 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws => ../ go.sum000066400000000000000000000115271443314701600357370ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/testgithub.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7 h1:yb2o8oh3Y+Gg2g+wlzrWS3pB89+dHrXayT/d9cs8McU= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.7/go.mod h1:1MNss6sqoIsFGisX92do/5doiUCBrN7EjhZCS/8DUjI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27 h1:QmyPCRZNMR1pFbiOi9kBZWZuKrKB9LD4cxltxQk4tNE= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.27/go.mod h1:DfuVY36ixXnsG+uTqnoLWunXAKJ4qjccoFrXUPpj+hs= github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1 h1:8e1fgdyer5IqBPtiWNsVLY/XFucmNTtYMqADyCFXTgQ= github.com/aws/aws-sdk-go-v2/service/route53 v1.28.1/go.mod h1:9SEpwqaALzp34eCT6w5PTh4SDDT84wxfMRx9VJSJPsk= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 h1:ikSvot5NdywduxtkOwOa2GJFzFuJq1ZjXsGjoIA82Ao= github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0/go.mod h1:ujUjm+PrcKUeIiKu2PT7MWjcyY0D6YZRZF3fSswiO+0= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020631443314701600366130ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test" // Version is the current release version of the AWS intstrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020521443314701600356320ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelaws // import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" // Version is the current release version of the AWS SDKv2 instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/000077500000000000000000000000001443314701600307325ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/000077500000000000000000000000001443314701600330225ustar00rootroot00000000000000memcache/000077500000000000000000000000001443314701600345055ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcacheotelmemcache/000077500000000000000000000000001443314701600371335ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcacheconfig.go000066400000000000000000000024521443314701600407320ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmemcache // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" import ( oteltrace "go.opentelemetry.io/otel/trace" ) type config struct { tracerProvider oteltrace.TracerProvider } // Option is used to configure the client. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider oteltrace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.tracerProvider = provider } }) } doc.go000066400000000000000000000020111443314701600402210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelmemcache instruments github.com/bradfitz/gomemcache/memcache. // // This instrumentation provided is tracing instrumentation for the memcached // client. // // The instrumentation works by wrapping the memcached client by calling // `NewClientWithTracing` and tracing it's every operation. package otelmemcache // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" example/000077500000000000000000000000001443314701600405665ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcacheDockerfile000066400000000000000000000014371443314701600425650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example FROM base AS memcache-client RUN go install ./client.go CMD ["/go/bin/client"] README.md000066400000000000000000000026541443314701600420540ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example# gomemcache instrumentation example A simple example to demonstrate gomemcache client tracing instrumentation. It consists of two containers - `memcached-server`, which initializes and runs the Memcached server for this example, and `gomemcache-client`, which is the instrumented client. In the example, the client invokes function `doMemcacheOperations()`, which is wrapped in a span. From within the function, the client will do a few example operations (add, get, delete with an intentional error) and cleans up the entries by calling `DeleteAll`. These instructions expect you to have [docker-compose](https://docs.docker.com/compose/) installed. # Running the example 1. From within the `example` directory, bring up the project by running: ```sh docker-compose up --detach ``` 2. The instrumentation works with a `stdout` exporter, meaning the spans should be visible in the output of the `gomemcache-container`. To inspect the output, you can run: ```sh docker-compose logs gomemcache-client ``` In the log, total of 5 spans should appear - the parent span `test-operations` and 4 child spans, each corresponding to one client operation. Additionally, the `Delete` operation span should also include `StatusCode` and `StatusMessage`, as this operation intentionally leads to an error. 3. After inspecting the client logs, the example can be cleaned up by running: ```sh docker-compose down ```client.go000066400000000000000000000042741443314701600424020ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "os" "github.com/bradfitz/gomemcache/memcache" "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" oteltracestdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func main() { var host, port = os.Getenv("HOST"), "11211" tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() ctx := context.Background() c := otelmemcache.NewClientWithTracing( memcache.New( host+":"+port, ), otelmemcache.WithTracerProvider(tp), ) ctx, s := tp.Tracer("example-tracer").Start(ctx, "test-operations") doMemcacheOperations(ctx, c) s.End() } func doMemcacheOperations(ctx context.Context, c *otelmemcache.Client) { cc := c.WithContext(ctx) err := cc.Add(&memcache.Item{ Key: "foo", Value: []byte("bar"), }) if err != nil { log.Printf("Add failed: %s", err) } _, err = cc.Get("foo") if err != nil { log.Printf("Get failed: %s", err) } err = cc.Delete("baz") if err != nil { log.Printf("Delete failed: %s", err) } err = cc.DeleteAll() if err != nil { log.Printf("DeleteAll failed: %s", err) } } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := oteltracestdout.New(oteltracestdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) return tp, nil } docker-compose.yml000066400000000000000000000017531443314701600442310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: gomemcache-client: build: dockerfile: $PWD/Dockerfile context: ../../../../../../.. command: - "/bin/sh" - "-c" - "/go/bin/client" environment: - HOST=memcached-server networks: - example depends_on: - memcached-server memcached-server: image: memcached:1.6.6-alpine networks: - example networks: example: go.mod000066400000000000000000000014521443314701600416760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache => ../ require ( github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache v0.42.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000041351443314701600417240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/examplegithub.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= go.mod000066400000000000000000000011171443314701600402410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcachemodule go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache go 1.19 require ( github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000041411443314701600402660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcachegithub.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gomemcache.go000066400000000000000000000146531443314701600415630ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmemcache // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" import ( "context" "github.com/bradfitz/gomemcache/memcache" "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/internal" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" oteltrace "go.opentelemetry.io/otel/trace" ) const ( tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" ) // Client is a wrapper around *memcache.Client. type Client struct { *memcache.Client tracer oteltrace.Tracer ctx context.Context } // NewClientWithTracing wraps the provided memcache client to allow // tracing of all client operations. Accepts options to set trace provider // and service name, otherwise uses registered global trace provider and // default value for service name. // // Every client operation starts a span with appropriate attributes, // executes the operation and ends the span (additionally also sets a status // error code and message, if an error occurs). Optionally, client context can // be set before an operation with the WithContext method. func NewClientWithTracing(client *memcache.Client, opts ...Option) *Client { cfg := &config{} for _, o := range opts { o.apply(cfg) } if cfg.tracerProvider == nil { cfg.tracerProvider = otel.GetTracerProvider() } return &Client{ client, cfg.tracerProvider.Tracer( tracerName, oteltrace.WithInstrumentationVersion(Version()), ), context.Background(), } } // attrsByOperationAndItemKey returns appropriate span attributes on the basis // of the operation name and item key(s) (if available). func (c *Client) attrsByOperationAndItemKey(operation internal.Operation, key ...string) []attribute.KeyValue { attributes := []attribute.KeyValue{ internal.MemcacheDBSystem(), internal.MemcacheDBOperation(operation), } if len(key) > 0 { attributes = append(attributes, internal.MemcacheDBItemKeys(key...)) } return attributes } // Starts span with appropriate span kind and attributes. func (c *Client) startSpan(operationName internal.Operation, itemKey ...string) oteltrace.Span { opts := []oteltrace.SpanStartOption{ // for database client calls, always use CLIENT span kind oteltrace.WithSpanKind(oteltrace.SpanKindClient), oteltrace.WithAttributes( c.attrsByOperationAndItemKey(operationName, itemKey...)..., ), } _, span := c.tracer.Start( c.ctx, string(operationName), opts..., ) return span } // Ends span and, if applicable, sets error status. func endSpan(s oteltrace.Span, err error) { if err != nil { s.SetStatus(codes.Error, err.Error()) } s.End() } // WithContext retruns a copy of the client with provided context. func (c *Client) WithContext(ctx context.Context) *Client { cc := c.Client return &Client{ Client: cc, tracer: c.tracer, ctx: ctx, } } // Add invokes the add operation and traces it. func (c *Client) Add(item *memcache.Item) error { s := c.startSpan(internal.OperationAdd, item.Key) err := c.Client.Add(item) endSpan(s, err) return err } // CompareAndSwap invokes the compare-and-swap operation and traces it. func (c *Client) CompareAndSwap(item *memcache.Item) error { s := c.startSpan(internal.OperationCompareAndSwap, item.Key) err := c.Client.CompareAndSwap(item) endSpan(s, err) return err } // Decrement invokes the decrement operation and traces it. func (c *Client) Decrement(key string, delta uint64) (uint64, error) { s := c.startSpan(internal.OperationDecrement, key) newValue, err := c.Client.Decrement(key, delta) endSpan(s, err) return newValue, err } // Delete invokes the delete operation and traces it. func (c *Client) Delete(key string) error { s := c.startSpan(internal.OperationDelete, key) err := c.Client.Delete(key) endSpan(s, err) return err } // DeleteAll invokes the delete all operation and traces it. func (c *Client) DeleteAll() error { s := c.startSpan(internal.OperationDeleteAll) err := c.Client.DeleteAll() endSpan(s, err) return err } // FlushAll invokes the flush all operation and traces it. func (c *Client) FlushAll() error { s := c.startSpan(internal.OperationFlushAll) err := c.Client.FlushAll() endSpan(s, err) return err } // Get invokes the get operation and traces it. func (c *Client) Get(key string) (*memcache.Item, error) { s := c.startSpan(internal.OperationGet, key) item, err := c.Client.Get(key) endSpan(s, err) return item, err } // GetMulti invokes the get operation for multiple keys and traces it. func (c *Client) GetMulti(keys []string) (map[string]*memcache.Item, error) { s := c.startSpan(internal.OperationGet, keys...) items, err := c.Client.GetMulti(keys) endSpan(s, err) return items, err } // Increment invokes the increment operation and traces it. func (c *Client) Increment(key string, delta uint64) (uint64, error) { s := c.startSpan(internal.OperationIncrement, key) newValue, err := c.Client.Increment(key, delta) endSpan(s, err) return newValue, err } // Ping invokes the ping operation and traces it. func (c *Client) Ping() error { s := c.startSpan(internal.OperationPing) err := c.Client.Ping() endSpan(s, err) return err } // Replace invokes the replace operation and traces it. func (c *Client) Replace(item *memcache.Item) error { s := c.startSpan(internal.OperationReplace, item.Key) err := c.Client.Replace(item) endSpan(s, err) return err } // Set invokes the set operation and traces it. func (c *Client) Set(item *memcache.Item) error { s := c.startSpan(internal.OperationSet, item.Key) err := c.Client.Set(item) endSpan(s, err) return err } // Touch invokes the touch operation and traces it. func (c *Client) Touch(key string, seconds int32) error { s := c.startSpan(internal.OperationTouch, key) err := c.Client.Touch(key, seconds) endSpan(s, err) return err } gomemcache_test.go000066400000000000000000000015571443314701600426210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmemcache import ( "testing" "github.com/bradfitz/gomemcache/memcache" "github.com/stretchr/testify/assert" ) func TestNewClientWithTracing(t *testing.T) { c := NewClientWithTracing( memcache.New(), ) assert.NotNil(t, c.Client) assert.NotNil(t, c.tracer) } internal/000077500000000000000000000000001443314701600407475ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcacheattributes.go000066400000000000000000000035671443314701600434770ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/internal// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/internal" import ( "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) type Operation string // Instrumentation specific tracing information. const ( OperationAdd Operation = "add" OperationCompareAndSwap Operation = "cas" OperationDecrement Operation = "decr" OperationDelete Operation = "delete" OperationDeleteAll Operation = "delete_all" OperationFlushAll Operation = "flush_all" OperationGet Operation = "get" OperationIncrement Operation = "incr" OperationPing Operation = "ping" OperationReplace Operation = "replace" OperationSet Operation = "set" OperationTouch Operation = "touch" MemcacheDBItemKeyName attribute.Key = "db.memcached.item" ) func MemcacheDBSystem() attribute.KeyValue { return semconv.DBSystemMemcached } func MemcacheDBOperation(opName Operation) attribute.KeyValue { return semconv.DBOperation(string(opName)) } func MemcacheDBItemKeys(itemKeys ...string) attribute.KeyValue { if len(itemKeys) > 1 { return MemcacheDBItemKeyName.StringSlice(itemKeys) } return MemcacheDBItemKeyName.String(itemKeys[0]) } test/000077500000000000000000000000001443314701600401125ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcachedoc.go000066400000000000000000000017301443314701600412070ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelmemcache instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test" go.mod000066400000000000000000000017351443314701600412260ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test go 1.19 require ( github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib v1.17.0 go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache => ../ replace go.opentelemetry.io/contrib => ../../../../../../../ go.sum000066400000000000000000000046511443314701600412530ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/testgithub.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gomemcache_test.go000066400000000000000000000061421443314701600435730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "os" "testing" "github.com/bradfitz/gomemcache/memcache" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/internal" "go.opentelemetry.io/contrib/internal/util" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" oteltrace "go.opentelemetry.io/otel/trace" ) func TestMain(m *testing.M) { util.IntegrationShouldRun("test-gomemcache") os.Exit(m.Run()) } func TestOperation(t *testing.T) { c, sr := initClientWithSpanRecorder(t) mi := &memcache.Item{ Key: "foo", Value: []byte("bar"), } err := c.Add(mi) require.NoError(t, err) spans := sr.Ended() assert.Len(t, spans, 1) assert.Equal(t, oteltrace.SpanKindClient, spans[0].SpanKind()) assert.Equal(t, string(internal.OperationAdd), spans[0].Name()) assert.Len(t, spans[0].Attributes(), 3) attrs := spans[0].Attributes() assert.Contains(t, attrs, internal.MemcacheDBSystem()) assert.Contains(t, attrs, internal.MemcacheDBOperation(internal.OperationAdd)) assert.Contains(t, attrs, internal.MemcacheDBItemKeyName.String(mi.Key)) } func TestOperationWithCacheMissError(t *testing.T) { key := "foo" c, sr := initClientWithSpanRecorder(t) _, err := c.Get(key) assert.Error(t, err) spans := sr.Ended() assert.Len(t, spans, 1) assert.Equal(t, oteltrace.SpanKindClient, spans[0].SpanKind()) assert.Equal(t, string(internal.OperationGet), spans[0].Name()) assert.Len(t, spans[0].Attributes(), 3) attrs := spans[0].Attributes() assert.Contains(t, attrs, internal.MemcacheDBSystem()) assert.Contains(t, attrs, internal.MemcacheDBOperation(internal.OperationGet)) assert.Contains(t, attrs, internal.MemcacheDBItemKeyName.String(key)) assert.Equal(t, codes.Error, spans[0].Status().Code) assert.Equal(t, err.Error(), spans[0].Status().Description) } // tests require running memcached instance. func initClientWithSpanRecorder(t *testing.T) (*otelmemcache.Client, *tracetest.SpanRecorder) { host, port := "localhost", "11211" mc := memcache.New(host + ":" + port) require.NoError(t, clearDB(mc)) sr := tracetest.NewSpanRecorder() c := otelmemcache.NewClientWithTracing( mc, otelmemcache.WithTracerProvider( trace.NewTracerProvider(trace.WithSpanProcessor(sr)), ), ) return c, sr } func clearDB(c *memcache.Client) error { return c.DeleteAll() } version.go000066400000000000000000000021101443314701600421200ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test" // Version is the current release version of the memcached instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020771443314701600411550ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmemcache // import "go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache" // Version is the current release version of the memcached instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/000077500000000000000000000000001443314701600307075ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/000077500000000000000000000000001443314701600327765ustar00rootroot00000000000000otelrestful/000077500000000000000000000000001443314701600352675ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restfulconfig.go000066400000000000000000000051271443314701600370700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelrestful // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" import ( "net/http" "go.opentelemetry.io/otel/propagation" oteltrace "go.opentelemetry.io/otel/trace" ) // config is used to configure the go-restful middleware. type config struct { TracerProvider oteltrace.TracerProvider Propagators propagation.TextMapPropagator PublicEndpoint bool PublicEndpointFn func(*http.Request) bool } // Option applies a configuration value. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithPublicEndpoint configures the Handler to link the span with an incoming // span context. If this option is not provided, then the association is a child // association instead of a link. func WithPublicEndpoint() Option { return optionFunc(func(c *config) { c.PublicEndpoint = true }) } // WithPropagators specifies propagators to use for extracting // information from the HTTP requests. If none are specified, global // ones will be used. func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagators != nil { cfg.Propagators = propagators } }) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider oteltrace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithPublicEndpointFn runs with every request, and allows conditionnally // configuring the Handler to link the span with an incoming span context. If // this option is not provided or returns false, then the association is a // child association instead of a link. // Note: [WithPublicEndpoint] takes precedence over WithPublicEndpointFn. func WithPublicEndpointFn(fn func(*http.Request) bool) Option { return optionFunc(func(c *config) { c.PublicEndpointFn = fn }) } doc.go000066400000000000000000000021441443314701600363640ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelrestful instruments github.com/emicklei/go-restful. // // Instrumentation is provided to trace the emicklei/go-restful/v3 // package (https://github.com/emicklei/go-restful). // // Instrumentation of an incoming request is achieved via a go-restful // FilterFunc called `OTelFilterFunc` which may be applied at any one of // - the container level // - webservice level // - route level package otelrestful // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" example/000077500000000000000000000000001443314701600367225ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestfulDockerfile000066400000000000000000000014271443314701600407200ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/emicklei/go-restful/otelrestful/example FROM base AS go-restful-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000014031443314701600401770ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/example# emicklei/go-restful instrumentation example An HTTP server using emicklei/go-restful and instrumentation. The server has a `/users/{id:[0-9]+}` endpoint. The server generates span information to `stdout`. These instructions assume you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `go-restful-server` and `go-restful-client` services to run the example: ```sh docker-compose up --detach go-restful-server go-restful-client ``` The `go-restful-client` service sends just one HTTP request to `go-restful-server` and then exits. View the span generated by `go-restful-server` in the logs: ```sh docker-compose logs go-restful-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000020741443314701600423620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: go-restful-client: image: golang:1.18-alpine networks: - example command: - "/bin/sh" - "-c" - "wget -O - http://go-restful-server:8080/users/123" depends_on: - go-restful-server go-restful-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example networks: example: go.mod000066400000000000000000000020001443314701600400200ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) require ( github.com/emicklei/go-restful/v3 v3.10.2 go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000063101443314701600400550ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/examplegithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server.go000066400000000000000000000060131443314701600405570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "net/http" "strconv" "github.com/emicklei/go-restful/v3" "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) var tracer oteltrace.Tracer type userResource struct{} func (u userResource) WebService() *restful.WebService { ws := &restful.WebService{} ws.Path("/users"). Consumes(restful.MIME_JSON). Produces(restful.MIME_JSON) ws.Route(ws.GET("/{user-id}").To(u.getUser). Param(ws.PathParameter("user-id", "identifier of the user").DataType("integer").DefaultValue("1")). Writes(user{}). // on the response Returns(http.StatusOK, "OK", user{}). Returns(http.StatusNotFound, "Not Found", nil)) return ws } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() u := userResource{} // create the Otel filter filter := otelrestful.OTelFilter("my-service") // use it restful.DefaultContainer.Filter(filter) restful.DefaultContainer.Add(u.WebService()) _ = http.ListenAndServe(":8080", nil) } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.Baggage{}, propagation.TraceContext{})) tracer = otel.GetTracerProvider().Tracer("go-restful-server", oteltrace.WithInstrumentationVersion("0.1")) return tp, nil } func (u userResource) getUser(req *restful.Request, resp *restful.Response) { uid := req.PathParameter("user-id") _, span := tracer.Start(req.Request.Context(), "getUser", oteltrace.WithAttributes(attribute.String("id", uid))) defer span.End() id, err := strconv.Atoi(uid) if err == nil && id >= 100 { _ = resp.WriteEntity(user{id}) return } _ = resp.WriteErrorString(http.StatusNotFound, "User could not be found.") } type user struct { ID int `json:"id" description:"identifier of the user"` } go.mod000066400000000000000000000017201443314701600363750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestfulmodule go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful go 1.19 replace go.opentelemetry.io/contrib/propagators/b3 => ../../../../../propagators/b3 require ( github.com/emicklei/go-restful/v3 v3.10.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000065371443314701600364350ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestfulgithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= restful.go000066400000000000000000000057461443314701600373160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelrestful // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" import ( "github.com/emicklei/go-restful/v3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" oteltrace "go.opentelemetry.io/otel/trace" ) const tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" // OTelFilter returns a restful.FilterFunction which will trace an incoming request. // // The service parameter should describe the name of the (virtual) server handling // the request. Options can be applied to configure the tracer and propagators // used for this filter. func OTelFilter(service string, opts ...Option) restful.FilterFunction { cfg := config{} for _, opt := range opts { opt.apply(&cfg) } if cfg.TracerProvider == nil { cfg.TracerProvider = otel.GetTracerProvider() } tracer := cfg.TracerProvider.Tracer( tracerName, oteltrace.WithInstrumentationVersion(Version()), ) if cfg.Propagators == nil { cfg.Propagators = otel.GetTextMapPropagator() } return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { r := req.Request ctx := cfg.Propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) route := req.SelectedRoutePath() spanName := route opts := []oteltrace.SpanStartOption{ oteltrace.WithAttributes(httpconv.ServerRequest(service, r)...), oteltrace.WithSpanKind(oteltrace.SpanKindServer), } if route != "" { rAttr := semconv.HTTPRoute(route) opts = append(opts, oteltrace.WithAttributes(rAttr)) } if cfg.PublicEndpoint || (cfg.PublicEndpointFn != nil && cfg.PublicEndpointFn(r.WithContext(ctx))) { opts = append(opts, oteltrace.WithNewRoot()) // Linking incoming span context if any for public endpoint. if s := oteltrace.SpanContextFromContext(ctx); s.IsValid() && s.IsRemote() { opts = append(opts, oteltrace.WithLinks(oteltrace.Link{SpanContext: s})) } } ctx, span := tracer.Start(ctx, spanName, opts...) defer span.End() // pass the span through the request context req.Request = req.Request.WithContext(ctx) chain.ProcessFilter(req, resp) status := resp.StatusCode() span.SetStatus(httpconv.ServerStatus(status)) if status > 0 { span.SetAttributes(semconv.HTTPStatusCode(status)) } } } restful_test.go000066400000000000000000000211361443314701600403440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelrestful_test import ( "context" "net/http" "net/http/httptest" "testing" "github.com/emicklei/go-restful/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" b3prop "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" oteltrace "go.opentelemetry.io/otel/trace" ) const tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" func TestGetSpanNotInstrumented(t *testing.T) { handlerFunc := func(req *restful.Request, resp *restful.Response) { span := oteltrace.SpanFromContext(req.Request.Context()) ok := !span.SpanContext().IsValid() assert.True(t, ok) resp.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Add(ws) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() container.ServeHTTP(w, r) } func TestPropagationWithGlobalPropagators(t *testing.T) { defer func(p propagation.TextMapPropagator) { otel.SetTextMapPropagator(p) }(otel.GetTextMapPropagator()) provider := oteltrace.NewNoopTracerProvider() otel.SetTextMapPropagator(propagation.TraceContext{}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, }) ctx = oteltrace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) handlerFunc := func(req *restful.Request, resp *restful.Response) { span := oteltrace.SpanFromContext(req.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) w.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("foobar", otelrestful.WithTracerProvider(provider))) container.Add(ws) container.ServeHTTP(w, r) } func TestPropagationWithCustomPropagators(t *testing.T) { provider := oteltrace.NewNoopTracerProvider() b3 := b3prop.New() r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, }) ctx = oteltrace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") b3.Inject(ctx, propagation.HeaderCarrier(r.Header)) handlerFunc := func(req *restful.Request, resp *restful.Response) { span := oteltrace.SpanFromContext(req.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) w.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("foobar", otelrestful.WithTracerProvider(provider), otelrestful.WithPropagators(b3))) container.Add(ws) container.ServeHTTP(w, r) } func TestWithPublicEndpoint(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) remoteSpan := oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, Remote: true, } prop := propagation.TraceContext{} handlerFunc := func(req *restful.Request, resp *restful.Response) { s := oteltrace.SpanFromContext(req.Request.Context()) sc := s.SpanContext() // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("test_handler", otelrestful.WithPublicEndpoint(), otelrestful.WithPropagators(prop), otelrestful.WithTracerProvider(provider)), ) container.Add(ws) r, err := http.NewRequest(http.MethodGet, "http://localhost/user/123", nil) require.NoError(t, err) sc := oteltrace.NewSpanContext(remoteSpan) ctx := oteltrace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r.Header)) rr := httptest.NewRecorder() container.ServeHTTP(rr, r) assert.Equal(t, 200, rr.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, spanRecorder.ForceFlush(ctx)) done := spanRecorder.Ended() require.Len(t, done, 1) require.Len(t, done[0].Links(), 1, "should contain link") require.True(t, sc.Equal(done[0].Links()[0].SpanContext), "should link incoming span context") } func TestWithPublicEndpointFn(t *testing.T) { remoteSpan := oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, TraceFlags: oteltrace.FlagsSampled, Remote: true, } prop := propagation.TraceContext{} for _, tt := range []struct { name string fn func(*http.Request) bool handlerAssert func(*testing.T, oteltrace.SpanContext) spansAssert func(*testing.T, oteltrace.SpanContext, []sdktrace.ReadOnlySpan) }{ { name: "with the method returning true", fn: func(r *http.Request) bool { return true }, handlerAssert: func(t *testing.T, sc oteltrace.SpanContext) { // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, sc oteltrace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 1, "should contain link") require.True(t, sc.Equal(spans[0].Links()[0].SpanContext), "should link incoming span context") }, }, { name: "with the method returning false", fn: func(r *http.Request) bool { return false }, handlerAssert: func(t *testing.T, sc oteltrace.SpanContext) { // Should have remote span as parent assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.Equal(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, _ oteltrace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 0, "should not contain link") }, }, } { t.Run(tt.name, func(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) handlerFunc := func(req *restful.Request, resp *restful.Response) { s := oteltrace.SpanFromContext(req.Request.Context()) tt.handlerAssert(t, s.SpanContext()) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("test_handler", otelrestful.WithPublicEndpointFn(tt.fn), otelrestful.WithPropagators(prop), otelrestful.WithTracerProvider(provider)), ) container.Add(ws) r, err := http.NewRequest(http.MethodGet, "http://localhost/user/123", nil) require.NoError(t, err) sc := oteltrace.NewSpanContext(remoteSpan) ctx := oteltrace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r.Header)) rr := httptest.NewRecorder() container.ServeHTTP(rr, r) assert.Equal(t, http.StatusOK, rr.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, spanRecorder.ForceFlush(ctx)) spans := spanRecorder.Ended() tt.spansAssert(t, sc, spans) }) } } test/000077500000000000000000000000001443314701600362465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestfuldoc.go000066400000000000000000000017151443314701600373460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelrestful instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/test" go.mod000066400000000000000000000021501443314701600373520ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/test go 1.19 require ( github.com/emicklei/go-restful/v3 v3.10.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace ( go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) go.sum000066400000000000000000000065371443314701600374140ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/testgithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= restful_test.go000066400000000000000000000150431443314701600413230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "net/http" "net/http/httptest" "strconv" "testing" "github.com/emicklei/go-restful/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" oteltrace "go.opentelemetry.io/otel/trace" ) func TestChildSpanFromGlobalTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))) handlerFunc := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc). Returns(http.StatusOK, "OK", nil). Returns(http.StatusNotFound, "Not Found", nil)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("my-service")) container.Add(ws) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() container.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) } func TestChildSpanFromCustomTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) handlerFunc := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("my-service", otelrestful.WithTracerProvider(provider))) container.Add(ws) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() container.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) } func TestChildSpanNames(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) handlerFunc := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(http.StatusOK) } ws := &restful.WebService{} ws.Route(ws.GET("/user/{id:[0-9]+}").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("foobar", otelrestful.WithTracerProvider(provider))) container.Add(ws) ws.Route(ws.GET("/book/{title}").To(func(req *restful.Request, resp *restful.Response) { _, _ = resp.Write(([]byte)("ok")) })) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() container.ServeHTTP(w, r) spans := sr.Ended() require.Len(t, spans, 1) assertSpan( t, spans[0], "/user/{id:[0-9]+}", attribute.String("net.host.name", "foobar"), attribute.Int("http.status_code", http.StatusOK), attribute.String("http.method", "GET"), attribute.String("http.route", "/user/{id:[0-9]+}"), ) r = httptest.NewRequest("GET", "/book/foo", nil) w = httptest.NewRecorder() container.ServeHTTP(w, r) spans = sr.Ended() require.Len(t, spans, 2) assertSpan( t, spans[1], "/book/{title}", attribute.String("net.host.name", "foobar"), attribute.Int("http.status_code", http.StatusOK), attribute.String("http.method", "GET"), attribute.String("http.route", "/book/{title}"), ) } func TestMultiFilters(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) retOK := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(http.StatusOK) } ws1 := &restful.WebService{} ws1.Path("/user") ws1.Route(ws1.GET("/{id}"). Filter(otelrestful.OTelFilter("my-service", otelrestful.WithTracerProvider(provider))). To(retOK)) ws1.Route(ws1.GET("/{id}/books"). Filter(otelrestful.OTelFilter("book-service", otelrestful.WithTracerProvider(provider))). To(retOK)) ws2 := &restful.WebService{} ws2.Path("/library") ws2.Filter(otelrestful.OTelFilter("library-service", otelrestful.WithTracerProvider(provider))) ws2.Route(ws2.GET("/{name}").To(retOK)) container := restful.NewContainer() container.Add(ws1) container.Add(ws2) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() container.ServeHTTP(w, r) spans := sr.Ended() require.Len(t, spans, 1) assertSpan(t, spans[0], "/user/{id}") r = httptest.NewRequest("GET", "/user/123/books", nil) w = httptest.NewRecorder() container.ServeHTTP(w, r) spans = sr.Ended() require.Len(t, spans, 2) assertSpan(t, spans[1], "/user/{id}/books") r = httptest.NewRequest("GET", "/library/metropolitan", nil) w = httptest.NewRecorder() container.ServeHTTP(w, r) spans = sr.Ended() require.Len(t, spans, 3) assertSpan(t, spans[2], "/library/{name}") } func TestSpanStatus(t *testing.T) { testCases := []struct { httpStatusCode int wantSpanStatus codes.Code }{ {http.StatusOK, codes.Unset}, {http.StatusBadRequest, codes.Unset}, {http.StatusInternalServerError, codes.Error}, } for _, tc := range testCases { t.Run(strconv.Itoa(tc.httpStatusCode), func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) handlerFunc := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(tc.httpStatusCode) } ws := &restful.WebService{} ws.Route(ws.GET("/").To(handlerFunc)) container := restful.NewContainer() container.Filter(otelrestful.OTelFilter("my-service", otelrestful.WithTracerProvider(provider))) container.Add(ws) container.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) require.Len(t, sr.Ended(), 1, "should emit a span") assert.Equal(t, sr.Ended()[0].Status().Code, tc.wantSpanStatus, "should only set Error status for HTTP statuses >= 500") }) } } func assertSpan(t *testing.T, span sdktrace.ReadOnlySpan, name string, attrs ...attribute.KeyValue) { assert.Equal(t, name, span.Name()) assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) gotA := span.Attributes() for _, a := range attrs { assert.Contains(t, gotA, a) } } version.go000066400000000000000000000020771443314701600402700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/test" // Version is the current release version of the go-restful instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020651443314701600373060ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/emicklei/go-restful/otelrestful// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelrestful // import "go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful" // Version is the current release version of the go-restful instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/000077500000000000000000000000001443314701600307775ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/000077500000000000000000000000001443314701600315545ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/000077500000000000000000000000001443314701600332155ustar00rootroot00000000000000doc.go000066400000000000000000000017721443314701600342410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelgin instruments the github.com/gin-gonic/gin package. // // Currently there are two ways the code can be instrumented. One is // instrumenting the routing of a received message (the Middleware function) // and instrumenting the response generation through template evaluation (the // HTML function). package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" example/000077500000000000000000000000001443314701600345715ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelginDockerfile000066400000000000000000000014011443314701600365570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/gin-gonic/gin/otelgin/example FROM base AS gin-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000012571443314701600360550ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/example# gin-gonic instrumentation example An HTTP server using gin-gonic and instrumentation. The server has a `/users/:id` endpoint. The server generates span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `gin-server` and `gin-client` services to run the example: ```sh docker-compose up --detach gin-server gin-client ``` The `gin-client` service sends just one HTTP request to `gin-server` and then exits. View the span generated by `gin-server` in the logs: ```sh docker-compose logs gin-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000020441443314701600402260ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: gin-client: image: golang:alpine networks: - example command: - "/bin/sh" - "-c" - "wget http://gin-server:8080/users/123 && cat 123" depends_on: - gin-server gin-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../../ ports: - "8080:8080" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example networks: example: go.mod000066400000000000000000000031311443314701600356750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) require ( github.com/gin-gonic/gin v1.8.2 go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-json v0.10.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/ugorji/go/codec v1.2.9 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) go.sum000066400000000000000000000234771443314701600357410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/examplegithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= server.go000066400000000000000000000050001443314701600364210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "html/template" "log" "net/http" "github.com/gin-gonic/gin" "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) var tracer = otel.Tracer("gin-server") func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() r := gin.New() r.Use(otelgin.Middleware("my-server")) tmplName := "user" tmplStr := "user {{ .name }} (id {{ .id }})\n" tmpl := template.Must(template.New(tmplName).Parse(tmplStr)) r.SetHTMLTemplate(tmpl) r.GET("/users/:id", func(c *gin.Context) { id := c.Param("id") name := getUser(c, id) otelgin.HTML(c, http.StatusOK, tmplName, gin.H{ "name": name, "id": id, }) }) _ = r.Run(":8080") } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func getUser(c *gin.Context, id string) string { // Pass the built-in `context.Context` object from http.Request to OpenTelemetry APIs // where required. It is available from gin.Context.Request.Context() _, span := tracer.Start(c.Request.Context(), "getUser", oteltrace.WithAttributes(attribute.String("id", id))) defer span.End() if id == "123" { return "otelgin tester" } return "unknown" } gintrace.go000066400000000000000000000104371443314701600352660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace.go package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" import ( "fmt" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" oteltrace "go.opentelemetry.io/otel/trace" ) const ( tracerKey = "otel-go-contrib-tracer" tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) // Middleware returns middleware that will trace incoming requests. // The service parameter should describe the name of the (virtual) // server handling the request. func Middleware(service string, opts ...Option) gin.HandlerFunc { cfg := config{} for _, opt := range opts { opt.apply(&cfg) } if cfg.TracerProvider == nil { cfg.TracerProvider = otel.GetTracerProvider() } tracer := cfg.TracerProvider.Tracer( tracerName, oteltrace.WithInstrumentationVersion(Version()), ) if cfg.Propagators == nil { cfg.Propagators = otel.GetTextMapPropagator() } return func(c *gin.Context) { for _, f := range cfg.Filters { if !f(c.Request) { // Serve the request to the next middleware // if a filter rejects the request. c.Next() return } } c.Set(tracerKey, tracer) savedCtx := c.Request.Context() defer func() { c.Request = c.Request.WithContext(savedCtx) }() ctx := cfg.Propagators.Extract(savedCtx, propagation.HeaderCarrier(c.Request.Header)) opts := []oteltrace.SpanStartOption{ oteltrace.WithAttributes(httpconv.ServerRequest(service, c.Request)...), oteltrace.WithSpanKind(oteltrace.SpanKindServer), } var spanName string if cfg.SpanNameFormatter == nil { spanName = c.FullPath() } else { spanName = cfg.SpanNameFormatter(c.Request) } if spanName == "" { spanName = fmt.Sprintf("HTTP %s route not found", c.Request.Method) } else { rAttr := semconv.HTTPRoute(spanName) opts = append(opts, oteltrace.WithAttributes(rAttr)) } ctx, span := tracer.Start(ctx, spanName, opts...) defer span.End() // pass the span through the request context c.Request = c.Request.WithContext(ctx) // serve the request to the next middleware c.Next() status := c.Writer.Status() span.SetStatus(httpconv.ServerStatus(status)) if status > 0 { span.SetAttributes(semconv.HTTPStatusCode(status)) } if len(c.Errors) > 0 { span.SetAttributes(attribute.String("gin.errors", c.Errors.String())) } } } // HTML will trace the rendering of the template as a child of the // span in the given context. This is a replacement for // gin.Context.HTML function - it invokes the original function after // setting up the span. func HTML(c *gin.Context, code int, name string, obj interface{}) { var tracer oteltrace.Tracer tracerInterface, ok := c.Get(tracerKey) if ok { tracer, ok = tracerInterface.(oteltrace.Tracer) } if !ok { tracer = otel.GetTracerProvider().Tracer( tracerName, oteltrace.WithInstrumentationVersion(Version()), ) } savedContext := c.Request.Context() defer func() { c.Request = c.Request.WithContext(savedContext) }() opt := oteltrace.WithAttributes(attribute.String("go.template", name)) _, span := tracer.Start(savedContext, "gin.renderer.html", opt) defer func() { if r := recover(); r != nil { err := fmt.Errorf("error rendering template:%s: %s", name, r) span.RecordError(err) span.SetStatus(codes.Error, "template failure") span.End() panic(r) } else { span.End() } }() c.HTML(code, name, obj) } gintrace_test.go000066400000000000000000000064751443314701600363340ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace_test.go package otelgin import ( "context" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" b3prop "go.opentelemetry.io/contrib/propagators/b3" ) func init() { gin.SetMode(gin.ReleaseMode) // silence annoying log msgs } func TestGetSpanNotInstrumented(t *testing.T) { router := gin.New() router.GET("/ping", func(c *gin.Context) { // Assert we don't have a span on the context. span := trace.SpanFromContext(c.Request.Context()) ok := !span.SpanContext().IsValid() assert.True(t, ok) _, _ = c.Writer.Write([]byte("ok")) }) r := httptest.NewRequest("GET", "/ping", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) response := w.Result() assert.Equal(t, http.StatusOK, response.StatusCode) } func TestPropagationWithGlobalPropagators(t *testing.T) { provider := trace.NewNoopTracerProvider() otel.SetTextMapPropagator(b3prop.New()) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) router := gin.New() router.Use(Middleware("foobar", WithTracerProvider(provider))) router.GET("/user/:id", func(c *gin.Context) { span := trace.SpanFromContext(c.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) }) router.ServeHTTP(w, r) } func TestPropagationWithCustomPropagators(t *testing.T) { provider := trace.NewNoopTracerProvider() b3 := b3prop.New() r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") b3.Inject(ctx, propagation.HeaderCarrier(r.Header)) router := gin.New() router.Use(Middleware("foobar", WithTracerProvider(provider), WithPropagators(b3))) router.GET("/user/:id", func(c *gin.Context) { span := trace.SpanFromContext(c.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) }) router.ServeHTTP(w, r) } go.mod000066400000000000000000000030271443314701600342460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelginmodule go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin go 1.19 replace go.opentelemetry.io/contrib/propagators/b3 => ../../../../../propagators/b3 require ( github.com/gin-gonic/gin v1.8.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-json v0.10.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ugorji/go/codec v1.2.9 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000230051443314701600342710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgingithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= option.go000066400000000000000000000057401443314701600350030ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/option.go package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" import ( "net/http" "go.opentelemetry.io/otel/propagation" oteltrace "go.opentelemetry.io/otel/trace" ) type config struct { TracerProvider oteltrace.TracerProvider Propagators propagation.TextMapPropagator Filters []Filter SpanNameFormatter SpanNameFormatter } // Filter is a predicate used to determine whether a given http.request should // be traced. A Filter must return true if the request should be traced. type Filter func(*http.Request) bool // SpanNameFormatter is used to set span name by http.request. type SpanNameFormatter func(r *http.Request) string // Option specifies instrumentation configuration options. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithPropagators specifies propagators to use for extracting // information from the HTTP requests. If none are specified, global // ones will be used. func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagators != nil { cfg.Propagators = propagators } }) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider oteltrace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithFilter adds a filter to the list of filters used by the handler. // If any filter indicates to exclude a request then the request will not be // traced. All filters must allow a request to be traced for a Span to be created. // If no filters are provided then all requests are traced. // Filters will be invoked for each processed request, it is advised to make them // simple and fast. func WithFilter(f ...Filter) Option { return optionFunc(func(c *config) { c.Filters = append(c.Filters, f...) }) } // WithSpanNameFormatter takes a function that will be called on every // request and the returned string will become the Span Name. func WithSpanNameFormatter(f func(r *http.Request) string) Option { return optionFunc(func(c *config) { c.SpanNameFormatter = f }) } test/000077500000000000000000000000001443314701600341155ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgindoc.go000066400000000000000000000016771443314701600352240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelgin instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/test" gintrace_test.go000066400000000000000000000206521443314701600373040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace_test.go package test import ( "errors" "html/template" "net/http" "net/http/httptest" "strconv" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/attribute" oteltrace "go.opentelemetry.io/otel/trace" ) func init() { gin.SetMode(gin.ReleaseMode) // silence annoying log msgs } func TestChildSpanFromGlobalTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))) router := gin.New() router.Use(otelgin.Middleware("foobar")) router.GET("/user/:id", func(c *gin.Context) {}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) } func TestChildSpanFromCustomTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) router.GET("/user/:id", func(c *gin.Context) {}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) } func TestTrace200(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) router.GET("/user/:id", func(c *gin.Context) { id := c.Param("id") _, _ = c.Writer.Write([]byte(id)) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() // do and verify the request router.ServeHTTP(w, r) response := w.Result() require.Equal(t, http.StatusOK, response.StatusCode) // verify traces look good spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "/user/:id", span.Name()) assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) attr := span.Attributes() assert.Contains(t, attr, attribute.String("net.host.name", "foobar")) assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusOK)) assert.Contains(t, attr, attribute.String("http.method", "GET")) assert.Contains(t, attr, attribute.String("http.route", "/user/:id")) } func TestError(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) // setup router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) // configure a handler that returns an error and 5xx status // code router.GET("/server_err", func(c *gin.Context) { _ = c.AbortWithError(http.StatusInternalServerError, errors.New("oh no")) }) r := httptest.NewRequest("GET", "/server_err", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) response := w.Result() assert.Equal(t, http.StatusInternalServerError, response.StatusCode) // verify the errors and status are correct spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "/server_err", span.Name()) attr := span.Attributes() assert.Contains(t, attr, attribute.String("net.host.name", "foobar")) assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusInternalServerError)) assert.Contains(t, attr, attribute.String("gin.errors", "Error #01: oh no\n")) // server errors set the status assert.Equal(t, codes.Error, span.Status().Code) } func TestSpanStatus(t *testing.T) { testCases := []struct { httpStatusCode int wantSpanStatus codes.Code }{ {http.StatusOK, codes.Unset}, {http.StatusBadRequest, codes.Unset}, {http.StatusInternalServerError, codes.Error}, } for _, tc := range testCases { t.Run(strconv.Itoa(tc.httpStatusCode), func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) router.GET("/", func(c *gin.Context) { c.Status(tc.httpStatusCode) }) router.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) require.Len(t, sr.Ended(), 1, "should emit a span") assert.Equal(t, sr.Ended()[0].Status().Code, tc.wantSpanStatus, "should only set Error status for HTTP statuses >= 500") }) } } func TestSpanName(t *testing.T) { testCases := []struct { requestPath string spanNameFormatter otelgin.SpanNameFormatter wantSpanName string }{ {"/user/1", nil, "/user/:id"}, {"/user/1", func(r *http.Request) string { return r.URL.Path }, "/user/1"}, } for _, tc := range testCases { t.Run(tc.requestPath, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider), otelgin.WithSpanNameFormatter(tc.spanNameFormatter))) router.GET("/user/:id", func(c *gin.Context) {}) router.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", tc.requestPath, nil)) require.Len(t, sr.Ended(), 1, "should emit a span") assert.Equal(t, sr.Ended()[0].Name(), tc.wantSpanName, "span name not correct") }) } } func TestHTML(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) // setup router := gin.New() router.Use(otelgin.Middleware("foobar", otelgin.WithTracerProvider(provider))) // add a template tmpl := template.Must(template.New("hello").Parse("hello {{.}}")) router.SetHTMLTemplate(tmpl) // a handler with an error and make the requests router.GET("/hello", func(c *gin.Context) { otelgin.HTML(c, http.StatusOK, "hello", "world") }) r := httptest.NewRequest("GET", "/hello", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) response := w.Result() assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, "hello world", w.Body.String()) // verify the errors and status are correct spans := sr.Ended() require.Len(t, spans, 2) var tspan sdktrace.ReadOnlySpan for _, s := range spans { // we need to pick up the span we're searching for, as the // order is not guaranteed within the buffer if s.Name() == "gin.renderer.html" { tspan = s break } } require.NotNil(t, tspan) assert.Contains(t, tspan.Attributes(), attribute.String("go.template", "hello")) } func TestWithFilter(t *testing.T) { t.Run("custom filter filtering route", func(t *testing.T) { sr := tracetest.NewSpanRecorder() otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))) router := gin.New() f := func(req *http.Request) bool { return req.URL.Path != "/healthcheck" } router.Use(otelgin.Middleware("foobar", otelgin.WithFilter(f))) router.GET("/healthcheck", func(c *gin.Context) {}) r := httptest.NewRequest("GET", "/healthcheck", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 0) }) t.Run("custom filter not filtering route", func(t *testing.T) { sr := tracetest.NewSpanRecorder() otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))) router := gin.New() f := func(req *http.Request) bool { return req.URL.Path != "/healthcheck" } router.Use(otelgin.Middleware("foobar", otelgin.WithFilter(f))) router.GET("/user/:id", func(c *gin.Context) {}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) }) } go.mod000066400000000000000000000033041443314701600352230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/test go 1.19 require ( github.com/gin-gonic/gin v1.8.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-json v0.10.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ugorji/go/codec v1.2.9 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin => ../ replace go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 go.sum000066400000000000000000000232661443314701600352610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/testgithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020561443314701600361340ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/test" // Version is the current release version of the gin instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020401443314701600351460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gin-gonic/gin/otelgin// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgin // import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" // Version is the current release version of the gin instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/000077500000000000000000000000001443314701600303175ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/000077500000000000000000000000001443314701600311065ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/000077500000000000000000000000001443314701600325615ustar00rootroot00000000000000config.go000066400000000000000000000070621443314701600343030ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/go-kit/kit/blob/3796a6b25f5c6c545454d3ed7187c4ced258083d/tracing/opencensus/endpoint_options.go package otelkit // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) // config holds the options for tracing an endpoint. type config struct { // TracerProvider provides access to instrumentation Tracers. TracerProvider trace.TracerProvider // IgnoreBusinessError if set to true will not treat a business error // identified through the endpoint.Failer interface as a span error. IgnoreBusinessError bool // Operation identifies the current operation and serves as a span name. Operation string // GetOperation is an optional function that can set the span name based on the existing operation // for the endpoint and information in the context. // // If the function is nil, or the returned operation is empty, the existing operation for the endpoint is used. GetOperation func(ctx context.Context, operation string) string // Attributes holds the default attributes for each span created by this middleware. Attributes []attribute.KeyValue // GetAttributes is an optional function that can extract trace attributes // from the context and add them to the span. GetAttributes func(ctx context.Context) []attribute.KeyValue } // Option configures an EndpointMiddleware. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(o *config) { if provider != nil { o.TracerProvider = provider } }) } // WithIgnoreBusinessError if set to true will not treat a business error // identified through the endpoint.Failer interface as a span error. func WithIgnoreBusinessError(val bool) Option { return optionFunc(func(o *config) { o.IgnoreBusinessError = val }) } // WithOperation sets an operation name for an endpoint. // Use this when you register a middleware for each endpoint. func WithOperation(operation string) Option { return optionFunc(func(o *config) { o.Operation = operation }) } // WithOperationGetter sets an operation name getter function in config. func WithOperationGetter(fn func(ctx context.Context, name string) string) Option { return optionFunc(func(o *config) { o.GetOperation = fn }) } // WithAttributes sets the default attributes for the spans created by the Endpoint tracer. func WithAttributes(attrs ...attribute.KeyValue) Option { return optionFunc(func(o *config) { o.Attributes = attrs }) } // WithAttributeGetter extracts additional attributes from the context. func WithAttributeGetter(fn func(ctx context.Context) []attribute.KeyValue) Option { return optionFunc(func(o *config) { o.GetAttributes = fn }) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/doc.go000066400000000000000000000021431443314701600336550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelkit instruments the github.com/go-kit/kit package. // // Compared to other instrumentation libraries provided by go-kit itself, // this package only provides instrumentation for the endpoint layer. // For instrumenting the transport layer, // look at the instrumentation libraries provided by go.opentelemetry.io/contrib. // Learn more about go-kit's layers at https://gokit.io/faq/#architecture-and-design. package otelkit // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" endpoint.go000066400000000000000000000070651443314701600346610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/go-kit/kit/blob/3796a6b25f5c6c545454d3ed7187c4ced258083d/tracing/opencensus/endpoint.go package otelkit // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/sd/lb" ) const ( tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" // defaultSpanName is the default endpoint span name to use. defaultSpanName = "gokit/endpoint" ) // EndpointMiddleware returns an Endpoint middleware, tracing a Go kit endpoint. // This endpoint middleware should be used in combination with a Go kit Transport // tracing middleware, generic OpenTelemetry transport middleware or custom before // and after transport functions. func EndpointMiddleware(options ...Option) endpoint.Middleware { cfg := &config{} for _, o := range options { o.apply(cfg) } if cfg.TracerProvider == nil { cfg.TracerProvider = otel.GetTracerProvider() } tracer := cfg.TracerProvider.Tracer( tracerName, trace.WithInstrumentationVersion(Version()), ) return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { operation := cfg.Operation if cfg.GetOperation != nil { if newOperation := cfg.GetOperation(ctx, operation); newOperation != "" { operation = newOperation } } spanName := operation if spanName == "" { spanName = defaultSpanName } opts := []trace.SpanStartOption{ trace.WithAttributes(cfg.Attributes...), trace.WithSpanKind(trace.SpanKindServer), } if cfg.GetAttributes != nil { opts = append(opts, trace.WithAttributes(cfg.GetAttributes(ctx)...)) } ctx, span := tracer.Start(ctx, spanName, opts...) defer span.End() defer func() { if err != nil { if lberr, ok := err.(lb.RetryError); ok { // Handle errors originating from lb.Retry. for idx, rawErr := range lberr.RawErrors { span.RecordError(rawErr, trace.WithAttributes( attribute.Int("gokit.lb.retry.count", idx+1), )) } span.RecordError(lberr.Final) span.SetStatus(codes.Error, lberr.Error()) return } // generic error span.RecordError(err) span.SetStatus(codes.Error, err.Error()) return } // Test for business error. Business errors are often // successful requests carrying a business failure that // the client can act upon and therefore do not count // as failed requests. if res, ok := response.(endpoint.Failer); ok && res.Failed() != nil { span.RecordError(res.Failed()) if !cfg.IgnoreBusinessError { span.SetStatus(codes.Error, res.Failed().Error()) } return } // no errors identified }() response, err = next(ctx, request) return } } } example/000077500000000000000000000000001443314701600341355ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkitDockerfile000066400000000000000000000013761443314701600361360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/go-kit/kit/otelkit/example FROM base AS kit-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000012611443314701600354140ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/example# go-kit instrumentation example An HTTP server using go-kit and instrumentation. The server has a `/users/{id:[0-9]+}` endpoint. The server generates span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `kit-server` and `kit-client` services to run the example: ```sh docker-compose up --detach kit-server kit-client ``` The `kit-client` service sends just one HTTP request to `kit-server` and then exits. View the span generated by `kit-server` in the logs: ```sh docker-compose logs kit-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000022171443314701600375740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: kit-client: image: golang:alpine networks: - example command: - "/bin/sh" - "-c" - "wget http://kit-server:8080/users/123 && cat 123" depends_on: - kit-server kit-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example networks: example: go.mod000066400000000000000000000014561443314701600352510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/example go 1.18 require ( github.com/gorilla/mux v1.8.0 go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit => ../ go.sum000066400000000000000000000050061443314701600352710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/examplegithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server.go000066400000000000000000000047531443314701600360030ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "fmt" "log" "net/http" "github.com/gorilla/mux" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" ) var tracer = otel.Tracer("kit-server") func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() ep := otelkit.EndpointMiddleware( otelkit.WithOperation("getUser"), )(func(ctx context.Context, request interface{}) (response interface{}, err error) { id := request.(string) name := getUser(ctx, id) reply := fmt.Sprintf("user %s (id %s)\n", name, id) return reply, nil }) r := mux.NewRouter() r.HandleFunc("/users/{id:[0-9]+}", func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] reply, _ := ep(r.Context(), id) _, _ = w.Write(([]byte)(reply.(string))) }) http.Handle("/", r) _ = http.ListenAndServe(":8080", nil) } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, err } func getUser(ctx context.Context, id string) string { _, span := tracer.Start(ctx, "getUser", oteltrace.WithAttributes(attribute.String("id", id))) defer span.End() if id == "123" { return "otelmux tester" } return "unknown" } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/go.mod000066400000000000000000000007041443314701600336700ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit go 1.19 require ( github.com/go-kit/kit v0.12.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-kit/log v0.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/go.sum000066400000000000000000000034701443314701600337200ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/test/000077500000000000000000000000001443314701600335405ustar00rootroot00000000000000doc.go000066400000000000000000000016741443314701600345650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelkit instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test" endpoint_test.go000066400000000000000000000175221443314701600366760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "testing" "github.com/go-kit/kit/endpoint" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) type contextKey string const ( operationKey = contextKey("operation") ) // compile time assertion. var _ endpoint.Failer = failedResponse{} type customError struct { message string } func (e customError) Error() string { return e.message } type failedResponse struct { err error } func (r failedResponse) Failed() error { return r.err } func passEndpoint(_ context.Context, req interface{}) (interface{}, error) { if err, _ := req.(error); err != nil { return nil, err } return req, nil } func TestEndpointMiddleware(t *testing.T) { t.Run("GlobalTracer", func(t *testing.T) { sr := tracetest.NewSpanRecorder() otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))) mw := otelkit.EndpointMiddleware() e := func(ctx context.Context, _ interface{}) (interface{}, error) { return nil, nil } _, _ = mw(e)(context.Background(), nil) assert.Len(t, sr.Ended(), 1) }) t.Run("DefaultOperationAndAttributes", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), otelkit.WithOperation("operation"), otelkit.WithAttributes(attribute.String("key", "value")), ) _, _ = mw(passEndpoint)(context.Background(), nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "operation", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Unset, span.Status().Code) assert.Contains(t, span.Attributes(), attribute.String("key", "value")) }) t.Run("OperationAndAttributesFromContext", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), otelkit.WithOperationGetter(func(ctx context.Context, name string) string { operation, _ := ctx.Value(operationKey).(string) return operation }), otelkit.WithAttributeGetter(func(ctx context.Context) []attribute.KeyValue { return []attribute.KeyValue{ attribute.String("key", "value"), } }), ) ctx := context.WithValue(context.Background(), operationKey, "operation") _, _ = mw(passEndpoint)(ctx, nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "operation", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Unset, span.Status().Code) assert.Contains(t, span.Attributes(), attribute.String("key", "value")) }) t.Run("Overrides", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), otelkit.WithOperation("operations"), otelkit.WithOperationGetter(func(ctx context.Context, name string) string { operation, _ := ctx.Value(operationKey).(string) return operation }), otelkit.WithAttributes(attribute.String("key", "value")), otelkit.WithAttributeGetter(func(ctx context.Context) []attribute.KeyValue { return []attribute.KeyValue{ attribute.String("key2", "value2"), } }), ) ctx := context.WithValue(context.Background(), operationKey, "other_operation") _, _ = mw(passEndpoint)(ctx, nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "other_operation", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Unset, span.Status().Code) assert.Contains(t, span.Attributes(), attribute.String("key", "value")) assert.Contains(t, span.Attributes(), attribute.String("key2", "value2")) }) t.Run("Error", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), ) ctx := context.Background() _, _ = mw(func(_ context.Context, req interface{}) (interface{}, error) { return nil, customError{"something went wrong"} })(ctx, nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "gokit/endpoint", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Error, span.Status().Code) events := span.Events() require.Len(t, events, 1) assert.Equal(t, "exception", events[0].Name) assert.Contains(t, events[0].Attributes, attribute.String("exception.type", "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test.customError")) assert.Contains(t, events[0].Attributes, attribute.String("exception.message", "something went wrong")) }) t.Run("BusinessError", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), ) ctx := context.Background() _, _ = mw(func(_ context.Context, req interface{}) (interface{}, error) { return failedResponse{err: customError{"some business error"}}, nil })(ctx, nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "gokit/endpoint", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Error, span.Status().Code) events := span.Events() require.Len(t, events, 1) assert.Equal(t, "exception", events[0].Name) assert.Contains(t, events[0].Attributes, attribute.String("exception.type", "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test.customError")) assert.Contains(t, events[0].Attributes, attribute.String("exception.message", "some business error")) }) t.Run("IgnoredBusinessError", func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) mw := otelkit.EndpointMiddleware( otelkit.WithTracerProvider(provider), otelkit.WithIgnoreBusinessError(true), ) ctx := context.Background() _, _ = mw(func(_ context.Context, req interface{}) (interface{}, error) { return failedResponse{err: customError{"some business error"}}, nil })(ctx, nil) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "gokit/endpoint", span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) assert.Equal(t, codes.Unset, span.Status().Code) events := span.Events() require.Len(t, events, 1) assert.Equal(t, "exception", events[0].Name) assert.Contains(t, events[0].Attributes, attribute.String("exception.type", "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test.customError")) assert.Contains(t, events[0].Attributes, attribute.String("exception.message", "some business error")) }) } go.mod000066400000000000000000000020371443314701600345710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test go 1.19 require ( github.com/go-kit/kit v0.12.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-kit/log v0.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit => ../ go.sum000066400000000000000000000066161443314701600346250ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/testgithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020561443314701600355000ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test" // Version is the current release version of the go-kit instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020401443314701600345120ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/go-kit/kit/otelkit// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelkit // import "go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit" // Version is the current release version of the go-kit instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/000077500000000000000000000000001443314701600302325ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/000077500000000000000000000000001443314701600313375ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/000077500000000000000000000000001443314701600333305ustar00rootroot00000000000000config.go000066400000000000000000000100501443314701600350410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" import ( "github.com/gocql/gocql" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" ) type config struct { tracerProvider trace.TracerProvider meterProvider metric.MeterProvider instrumentQuery bool instrumentBatch bool instrumentConnect bool queryObserver gocql.QueryObserver batchObserver gocql.BatchObserver connectObserver gocql.ConnectObserver } // Option applies a configuration option. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithQueryObserver sets an additional QueryObserver to the session configuration. Use this if // there is an existing QueryObserver that you would like called. It will be called after the // OpenTelemetry implementation, if it is not nil. Defaults to nil. func WithQueryObserver(observer gocql.QueryObserver) Option { return optionFunc(func(cfg *config) { cfg.queryObserver = observer }) } // WithBatchObserver sets an additional BatchObserver to the session configuration. Use this if // there is an existing BatchObserver that you would like called. It will be called after the // OpenTelemetry implementation, if it is not nil. Defaults to nil. func WithBatchObserver(observer gocql.BatchObserver) Option { return optionFunc(func(cfg *config) { cfg.batchObserver = observer }) } // WithConnectObserver sets an additional ConnectObserver to the session configuration. Use this if // there is an existing ConnectObserver that you would like called. It will be called after the // OpenTelemetry implementation, if it is not nil. Defaults to nil. func WithConnectObserver(observer gocql.ConnectObserver) Option { return optionFunc(func(cfg *config) { cfg.connectObserver = observer }) } // WithTracerProvider will set the trace provider used to get a tracer // for creating spans. Defaults to TracerProvider(). func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(c *config) { if provider != nil { c.tracerProvider = provider } }) } // WithMeterProvider will set the meter provider used to get a meter // for creating instruments. // Defaults to global.GetMeterProvider(). func WithMeterProvider(provider metric.MeterProvider) Option { return optionFunc(func(c *config) { if provider != nil { c.meterProvider = provider } }) } // WithQueryInstrumentation will enable and disable instrumentation of // queries. Defaults to enabled. func WithQueryInstrumentation(enabled bool) Option { return optionFunc(func(cfg *config) { cfg.instrumentQuery = enabled }) } // WithBatchInstrumentation will enable and disable insturmentation of // batch queries. Defaults to enabled. func WithBatchInstrumentation(enabled bool) Option { return optionFunc(func(cfg *config) { cfg.instrumentBatch = enabled }) } // WithConnectInstrumentation will enable and disable instrumentation of // connection attempts. Defaults to enabled. func WithConnectInstrumentation(enabled bool) Option { return optionFunc(func(cfg *config) { cfg.instrumentConnect = enabled }) } func newConfig(options ...Option) *config { cfg := &config{ tracerProvider: otel.GetTracerProvider(), meterProvider: otel.GetMeterProvider(), instrumentQuery: true, instrumentBatch: true, instrumentConnect: true, } for _, apply := range options { apply.apply(cfg) } return cfg } doc.go000066400000000000000000000014061443314701600343460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelgocql instruments the github.com/gocql/gocql package. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" example/000077500000000000000000000000001443314701600347045ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocqlREADME.md000066400000000000000000000010521443314701600361610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/example## Integration Example ### To run the example: 1. `cd` into the example directory. 2. Run `docker-compose up`. 3. Wait for cassandra to listen for cql clients with the following message in the logs: ``` Server.java:159 - Starting listening for CQL clients on /0.0.0.0:9042 (unencrypted)... ``` 4. Run the example using `go run .`. 5. You can view the spans in the browser at `localhost:9411` and the metrics at `localhost:2222`. ### When you're done: 1. `ctrl+c` to stop the example program. 2. `docker-compose down` to stop cassandra and zipkin. client.go000066400000000000000000000132451443314701600365160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build go1.18 // +build go1.18 package main // This example will create the keyspace // "gocql_integration_example" and a single table // with the following schema: // gocql_integration_example.book // id UUID // title text // author_first_name text // author_last_name text // PRIMARY KEY(id) // The example will insert fictional books into the database and // then truncate the table. import ( "context" "fmt" "log" "net/http" "os" "os/signal" "sync" "time" "github.com/gocql/gocql" "github.com/prometheus/client_golang/prometheus/promhttp" "go.opentelemetry.io/otel" otelprom "go.opentelemetry.io/otel/exporters/prometheus" "go.opentelemetry.io/otel/exporters/zipkin" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/aggregation" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" ) const keyspace = "gocql_integration_example" var wg sync.WaitGroup func main() { if err := initMetrics(); err != nil { log.Fatalf("failed to install metric exporter, %v", err) } tp, err := initTracer() if err != nil { log.Fatalf("failed to create zipkin exporter: %s", err) } defer func() { tp.Shutdown(context.Background()) }() //nolint:revive,errcheck if err := initDb(); err != nil { log.Fatal(err) } ctx, span := otel.Tracer( "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/example", ).Start(context.Background(), "begin example") cluster := getCluster() // Create a session to begin making queries session, err := otelgocql.NewSessionWithTracing( ctx, cluster, ) if err != nil { log.Fatalf("failed to create a session, %v", err) } defer session.Close() batch := session.NewBatch(gocql.LoggedBatch) for i := 0; i < 500; i++ { batch.Query( "INSERT INTO book (id, title, author_first_name, author_last_name) VALUES (?, ?, ?, ?)", gocql.TimeUUID(), fmt.Sprintf("Example Book %d", i), "firstName", "lastName", ) } if err := session.ExecuteBatch(batch.WithContext(ctx)); err != nil { log.Printf("failed to batch insert, %v", err) } res := session.Query( "SELECT title, author_first_name, author_last_name from book WHERE author_last_name = ?", "lastName", ).WithContext(ctx).PageSize(100).Iter() var ( title string firstName string lastName string ) for res.Scan(&title, &firstName, &lastName) { res.Scan(&title, &firstName, &lastName) } res.Close() if err = session.Query("truncate table book").WithContext(ctx).Exec(); err != nil { log.Printf("failed to delete data, %v", err) } span.End() wg.Wait() } func views() []metric.View { return []metric.View{ metric.NewView( metric.Instrument{ Name: "db.cassandra.rows", }, metric.Stream{ Aggregation: aggregation.ExplicitBucketHistogram{ Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10}, }, }, ), metric.NewView( metric.Instrument{Name: "db.cassandra.latency"}, metric.Stream{ Aggregation: aggregation.ExplicitBucketHistogram{ Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10}, }, }, ), } } func initMetrics() error { vs := views() exporter, err := otelprom.New() if err != nil { return err } provider := metric.NewMeterProvider( metric.WithReader(exporter), metric.WithView(vs...), ) otel.SetMeterProvider(provider) http.Handle("/", promhttp.Handler()) log.Print("Serving metrics at :2222/") go func() { err := http.ListenAndServe(":2222", nil) if err != nil { log.Print(err) } }() ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt) wg.Add(1) go func() { defer wg.Done() <-ctx.Done() err := provider.Shutdown(context.Background()) if err != nil { log.Printf("error stopping MeterProvider: %s", err) } }() return nil } func initTracer() (*trace.TracerProvider, error) { exporter, err := zipkin.New("http://localhost:9411/api/v2/spans") if err != nil { return nil, err } tp := trace.NewTracerProvider(trace.WithBatcher(exporter)) otel.SetTracerProvider(tp) return tp, nil } func initDb() error { cluster := gocql.NewCluster("127.0.0.1") cluster.Keyspace = "system" cluster.Consistency = gocql.LocalQuorum cluster.Timeout = time.Second * 2 session, err := cluster.CreateSession() if err != nil { return err } stmt := fmt.Sprintf( "create keyspace if not exists %s with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }", keyspace, ) if err := session.Query(stmt).Exec(); err != nil { return err } cluster.Keyspace = keyspace session, err = cluster.CreateSession() if err != nil { return err } stmt = "create table if not exists book(id UUID, title text, author_first_name text, author_last_name text, PRIMARY KEY(id))" if err = session.Query(stmt).Exec(); err != nil { return err } return session.Query("create index if not exists on book(author_last_name)").Exec() } func getCluster() *gocql.ClusterConfig { cluster := gocql.NewCluster("127.0.0.1") cluster.Keyspace = keyspace cluster.Consistency = gocql.LocalQuorum cluster.ProtoVersion = 3 cluster.Timeout = 2 * time.Second return cluster } doc.go000066400000000000000000000012551443314701600360030ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package main provides an example use of the otelgocql instrumentation. package main docker-compose.yml000066400000000000000000000013441443314701600403430ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: '3' services: cassandra: image: cassandra:3 ports: - 9042:9042 zipkin: image: openzipkin/zipkin:2 ports: - 9411:9411 go.mod000066400000000000000000000026631443314701600360210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql => ../ require ( github.com/gocql/gocql v1.4.0 github.com/prometheus/client_golang v1.15.1 go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/prometheus v0.39.0 go.opentelemetry.io/otel/exporters/zipkin v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect ) go.sum000066400000000000000000000153221443314701600360420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/examplegithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gocql/gocql v1.4.0 h1:NIlXAJXsjzjGvVn36njh9OLYWzS3D7FdvsifLj4eDEY= github.com/gocql/gocql v1.4.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/prometheus v0.39.0 h1:whAaiHxOatgtKd+w0dOi//1KUxj3KoPINZdtDaDj3IA= go.opentelemetry.io/otel/exporters/prometheus v0.39.0/go.mod h1:4jo5Q4CROlCpSPsXLhymi+LYrDXd2ObU5wbKayfZs7Y= go.opentelemetry.io/otel/exporters/zipkin v1.16.0 h1:WdMSH6vIJ+myJfr/HB/pjsYoJWQP0Wz/iJ1haNO5hX4= go.opentelemetry.io/otel/exporters/zipkin v1.16.0/go.mod h1:QjDOKdylighHJBc7pf4Vo6fdhtiEJEqww/3Df8TOWjo= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= example_session_test.go000066400000000000000000000020041443314701600400310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql import ( "context" "log" "github.com/gocql/gocql" ) func ExampleNewSessionWithTracing() { // Create a cluster host := "localhost" cluster := gocql.NewCluster(host) // Create a session with tracing _, err := NewSessionWithTracing( context.Background(), cluster, // Include any options here ) if err != nil { log.Fatalf("failed to create session, %v", err) } // Begin using the session } go.mod000066400000000000000000000012541443314701600343610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocqlmodule go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql go 1.19 require ( github.com/gocql/gocql v1.4.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000072421443314701600344110ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocqlgithub.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gocql/gocql v1.4.0 h1:NIlXAJXsjzjGvVn36njh9OLYWzS3D7FdvsifLj4eDEY= github.com/gocql/gocql v1.4.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gocql.go000066400000000000000000000037171443314701600347150ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" import ( "context" "github.com/gocql/gocql" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" "go.opentelemetry.io/otel/trace" ) // NewSessionWithTracing creates a new session using the given cluster // configuration enabling tracing for queries, batch queries, and connection attempts. // You may use additional observers and disable specific tracing using the provided `TracedSessionOption`s. func NewSessionWithTracing(ctx context.Context, cluster *gocql.ClusterConfig, options ...Option) (*gocql.Session, error) { cfg := newConfig(options...) instruments := newInstruments(cfg.meterProvider) tracer := cfg.tracerProvider.Tracer( internal.InstrumentationName, trace.WithInstrumentationVersion(Version()), ) cluster.QueryObserver = &OTelQueryObserver{ enabled: cfg.instrumentQuery, observer: cfg.queryObserver, tracer: tracer, inst: instruments, } cluster.BatchObserver = &OTelBatchObserver{ enabled: cfg.instrumentBatch, observer: cfg.batchObserver, tracer: tracer, inst: instruments, } cluster.ConnectObserver = &OTelConnectObserver{ ctx: ctx, enabled: cfg.instrumentConnect, observer: cfg.connectObserver, tracer: tracer, inst: instruments, } return cluster.CreateSession() } gocql_test.go000066400000000000000000000026201443314701600357440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) func TestHostOrIP(t *testing.T) { hostAndPort := "127.0.0.1:9042" attribute := internal.HostOrIP(hostAndPort) assert.Equal(t, semconv.NetSockPeerAddrKey, attribute.Key) assert.Equal(t, "127.0.0.1", attribute.Value.AsString()) hostAndPort = "exampleHost:9042" attribute = internal.HostOrIP(hostAndPort) assert.Equal(t, semconv.NetPeerNameKey, attribute.Key) assert.Equal(t, "exampleHost", attribute.Value.AsString()) hostAndPort = "invalid-host-and-port-string" attribute = internal.HostOrIP(hostAndPort) require.Empty(t, attribute.Value.AsString()) } instrument.go000066400000000000000000000054151443314701600360150ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" import ( "log" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" "go.opentelemetry.io/otel/metric" ) type instruments struct { // queryCount is the number of queries executed. queryCount metric.Int64Counter // queryRows is the number of rows returned by a query. queryRows metric.Int64Histogram // batchCount is the number of batch queries executed. batchCount metric.Int64Counter // connectionCount is the number of connections made // with the traced session. connectionCount metric.Int64Counter // latency is the sum of attempt latencies. latency metric.Int64Histogram } // newInstruments will create instruments using a meter // from the given provider p. func newInstruments(p metric.MeterProvider) *instruments { meter := p.Meter( internal.InstrumentationName, metric.WithInstrumentationVersion(Version()), ) instruments := &instruments{} var err error if instruments.queryCount, err = meter.Int64Counter( "db.cassandra.queries", metric.WithDescription("Number queries executed"), ); err != nil { log.Printf("failed to create iQueryCount instrument, %v", err) } if instruments.queryRows, err = meter.Int64Histogram( "db.cassandra.rows", metric.WithDescription("Number of rows returned from query"), ); err != nil { log.Printf("failed to create iQueryRows instrument, %v", err) } if instruments.batchCount, err = meter.Int64Counter( "db.cassandra.batch.queries", metric.WithDescription("Number of batch queries executed"), ); err != nil { log.Printf("failed to create iBatchCount instrument, %v", err) } if instruments.connectionCount, err = meter.Int64Counter( "db.cassandra.connections", metric.WithDescription("Number of connections created"), ); err != nil { log.Printf("failed to create iConnectionCount instrument, %v", err) } if instruments.latency, err = meter.Int64Histogram( "db.cassandra.latency", metric.WithDescription("Sum of latency to host in milliseconds"), metric.WithUnit("ms"), ); err != nil { log.Printf("failed to create iLatency instrument, %v", err) } return instruments } internal/000077500000000000000000000000001443314701600350655ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocqlcass.go000066400000000000000000000145731443314701600363570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/internal// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" import ( "log" "net" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const ( // CassVersionKey is the key for the attribute/label describing // the cql version. CassVersionKey = attribute.Key("db.cassandra.version") // CassHostIDKey is the key for the attribute/label describing the id // of the host being queried. CassHostIDKey = attribute.Key("db.cassandra.host.id") // CassHostStateKey is the key for the attribute/label describing // the state of the casssandra server hosting the node being queried. CassHostStateKey = attribute.Key("db.cassandra.host.state") // CassBatchQueriesKey is the key for the attribute describing // the number of queries contained within the batch statement. CassBatchQueriesKey = attribute.Key("db.cassandra.batch.queries") // CassErrMsgKey is the key for the attribute/label describing // the error message from an error encountered when executing a query, batch, // or connection attempt to the cassandra server. CassErrMsgKey = attribute.Key("db.cassandra.error.message") // CassRowsReturnedKey is the key for the span attribute describing the number of rows // returned on a query to the database. CassRowsReturnedKey = attribute.Key("db.cassandra.rows.returned") // CassQueryAttemptsKey is the key for the span attribute describing the number of attempts // made for the query in question. CassQueryAttemptsKey = attribute.Key("db.cassandra.attempts") // CassBatchQueryName is the batch operation span name. CassBatchQueryName = "Batch Query" // CassConnectName is the connect operation span name. CassConnectName = "New Connection" // InstrumentationName is the name of the instrumentation package. InstrumentationName = "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" ) // ------------------------------------------ Connection-level Attributes // CassDBSystem returns the name of the DB system, // cassandra, as a KeyValue pair (db.system). func CassDBSystem() attribute.KeyValue { return semconv.DBSystemCassandra } // CassPeerName returns the hostname of the cassandra // server as a semconv KeyValue pair (net.peer.name). func CassPeerName(name string) attribute.KeyValue { return semconv.NetPeerName(name) } // CassPeerPort returns the port number of the cassandra // server as a semconv KeyValue pair (net.peer.port). func CassPeerPort(port int) attribute.KeyValue { return semconv.NetPeerPort(port) } // CassPeerIP returns the IP address of the cassandra // server as a semconv KeyValue pair (net.peer.ip). func CassPeerIP(ip string) attribute.KeyValue { return semconv.NetSockPeerAddr(ip) } // CassVersion returns the cql version as a KeyValue pair. func CassVersion(version string) attribute.KeyValue { return CassVersionKey.String(version) } // CassHostID returns the id of the cassandra host as a KeyValue pair. func CassHostID(id string) attribute.KeyValue { return CassHostIDKey.String(id) } // CassHostState returns the state of the cassandra host as a KeyValue pair. func CassHostState(state string) attribute.KeyValue { return CassHostStateKey.String(state) } // ------------------------------------------ Call-level attributes // CassStatement returns the statement made to the cassandra database as a // semconv KeyValue pair (db.statement). func CassStatement(stmt string) attribute.KeyValue { return semconv.DBStatement(stmt) } // CassBatchQueryOperation returns the batch query operation // as a semconv KeyValue pair (db.operation). This is used in lieu of a // db.statement, which is not feasible to include in a span for a batch query // because there can be n different query statements in a batch query. func CassBatchQueryOperation() attribute.KeyValue { cassBatchQueryOperation := "db.cassandra.batch.query" return semconv.DBOperation(cassBatchQueryOperation) } // CassConnectOperation returns the connect operation // as a semconv KeyValue pair (db.operation). This is used in lieu of a // db.statement since connection creation does not have a CQL statement. func CassConnectOperation() attribute.KeyValue { cassConnectOperation := "db.cassandra.connect" return semconv.DBOperation(cassConnectOperation) } // CassKeyspace returns the keyspace of the session as // a semconv KeyValue pair (db.name). func CassKeyspace(keyspace string) attribute.KeyValue { return semconv.DBName(keyspace) } // CassBatchQueries returns the number of queries in a batch query // as a KeyValue pair. func CassBatchQueries(num int) attribute.KeyValue { return CassBatchQueriesKey.Int(num) } // CassErrMsg returns the KeyValue pair of an error message // encountered when executing a query, batch query, or error. func CassErrMsg(msg string) attribute.KeyValue { return CassErrMsgKey.String(msg) } // CassRowsReturned returns the KeyValue pair of the number of rows // returned from a query. func CassRowsReturned(rows int) attribute.KeyValue { return CassRowsReturnedKey.Int(rows) } // CassQueryAttempts returns the KeyValue pair of the number of attempts // made for a query. func CassQueryAttempts(num int) attribute.KeyValue { return CassQueryAttemptsKey.Int(num) } // HostOrIP returns a KeyValue pair for the hostname // retrieved from gocql.HostInfo.HostnameAndPort(). If the hostname // is returned as a resolved IP address (as is the case for localhost), // then the KeyValue will have the key net.peer.ip. // If the hostname is the proper DNS name, then the key will be net.peer.name. func HostOrIP(hostnameAndPort string) attribute.KeyValue { hostname, _, err := net.SplitHostPort(hostnameAndPort) if err != nil { log.Printf("failed to parse hostname from port, %v", err) } if parse := net.ParseIP(hostname); parse != nil { return CassPeerIP(parse.String()) } return CassPeerName(hostname) } observer.go000066400000000000000000000154711443314701600354370ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" import ( "context" "time" "github.com/gocql/gocql" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" ) // OTelQueryObserver implements the gocql.QueryObserver interface // to provide instrumentation to gocql queries. type OTelQueryObserver struct { enabled bool observer gocql.QueryObserver tracer trace.Tracer inst *instruments } // OTelBatchObserver implements the gocql.BatchObserver interface // to provide instrumentation to gocql batch queries. type OTelBatchObserver struct { enabled bool observer gocql.BatchObserver tracer trace.Tracer inst *instruments } // OTelConnectObserver implements the gocql.ConnectObserver interface // to provide instrumentation to connection attempts made by the session. type OTelConnectObserver struct { ctx context.Context enabled bool observer gocql.ConnectObserver tracer trace.Tracer inst *instruments } // ------------------------------------------ Observer Functions // ObserveQuery is called once per query, and provides instrumentation for it. func (o *OTelQueryObserver) ObserveQuery(ctx context.Context, observedQuery gocql.ObservedQuery) { if o.enabled { host := observedQuery.Host keyspace := observedQuery.Keyspace inst := o.inst attributes := includeKeyValues(host, internal.CassKeyspace(keyspace), internal.CassStatement(observedQuery.Statement), internal.CassRowsReturned(observedQuery.Rows), internal.CassQueryAttempts(observedQuery.Metrics.Attempts), ) ctx, span := o.tracer.Start( ctx, observedQuery.Statement, trace.WithTimestamp(observedQuery.Start), trace.WithAttributes(attributes...), trace.WithSpanKind(trace.SpanKindClient), ) if observedQuery.Err != nil { attributes = includeKeyValues( host, internal.CassKeyspace(keyspace), internal.CassStatement(observedQuery.Statement), internal.CassErrMsg(observedQuery.Err.Error()), ) span.SetAttributes(internal.CassErrMsg(observedQuery.Err.Error())) inst.queryCount.Add(ctx, 1, metric.WithAttributes(attributes...)) } else { attributes = includeKeyValues( host, internal.CassKeyspace(keyspace), internal.CassStatement(observedQuery.Statement), ) inst.queryCount.Add(ctx, 1, metric.WithAttributes(attributes...)) } span.End(trace.WithTimestamp(observedQuery.End)) o := metric.WithAttributes(includeKeyValues(host, internal.CassKeyspace(keyspace))...) inst.queryRows.Record(ctx, int64(observedQuery.Rows), o) inst.latency.Record(ctx, nanoToMilliseconds(observedQuery.Metrics.TotalLatency), o) } if o.observer != nil { o.observer.ObserveQuery(ctx, observedQuery) } } // ObserveBatch is called once per batch query, and provides instrumentation for it. func (o *OTelBatchObserver) ObserveBatch(ctx context.Context, observedBatch gocql.ObservedBatch) { if o.enabled { host := observedBatch.Host keyspace := observedBatch.Keyspace inst := o.inst attributes := includeKeyValues(host, internal.CassKeyspace(keyspace), internal.CassBatchQueryOperation(), internal.CassBatchQueries(len(observedBatch.Statements)), ) ctx, span := o.tracer.Start( ctx, internal.CassBatchQueryName, trace.WithTimestamp(observedBatch.Start), trace.WithAttributes(attributes...), trace.WithSpanKind(trace.SpanKindClient), ) if observedBatch.Err != nil { attributes = includeKeyValues( host, internal.CassKeyspace(keyspace), internal.CassErrMsg(observedBatch.Err.Error()), ) span.SetAttributes(internal.CassErrMsg(observedBatch.Err.Error())) inst.batchCount.Add(ctx, 1, metric.WithAttributes(attributes...)) } else { attributes = includeKeyValues(host, internal.CassKeyspace(keyspace)) inst.batchCount.Add(ctx, 1, metric.WithAttributes(attributes...)) } span.End(trace.WithTimestamp(observedBatch.End)) o := metric.WithAttributes(includeKeyValues(host, internal.CassKeyspace(keyspace))...) inst.latency.Record(ctx, nanoToMilliseconds(observedBatch.Metrics.TotalLatency), o) } if o.observer != nil { o.observer.ObserveBatch(ctx, observedBatch) } } // ObserveConnect is called once per connection attempt, and provides instrumentation for it. func (o *OTelConnectObserver) ObserveConnect(observedConnect gocql.ObservedConnect) { if o.enabled { host := observedConnect.Host inst := o.inst attributes := includeKeyValues(host, internal.CassConnectOperation()) _, span := o.tracer.Start( o.ctx, internal.CassConnectName, trace.WithTimestamp(observedConnect.Start), trace.WithAttributes(attributes...), trace.WithSpanKind(trace.SpanKindClient), ) if observedConnect.Err != nil { attributes = includeKeyValues(host, internal.CassErrMsg(observedConnect.Err.Error())) span.SetAttributes(internal.CassErrMsg(observedConnect.Err.Error())) inst.connectionCount.Add(o.ctx, 1, metric.WithAttributes(attributes...)) } else { attributes = includeKeyValues(host) inst.connectionCount.Add(o.ctx, 1, metric.WithAttributes(attributes...)) } span.End(trace.WithTimestamp(observedConnect.End)) } if o.observer != nil { o.observer.ObserveConnect(observedConnect) } } // ------------------------------------------ Private Functions // includeKeyValues is a convenience function for adding multiple attributes/labels to a // span or instrument. By default, this function includes connection-level attributes, // (as per the semantic conventions) which have been made standard for all spans and metrics // generated by this instrumentation integration. func includeKeyValues(host *gocql.HostInfo, values ...attribute.KeyValue) []attribute.KeyValue { connectionLevelAttributes := []attribute.KeyValue{ internal.CassDBSystem(), internal.HostOrIP(host.HostnameAndPort()), internal.CassPeerPort(host.Port()), internal.CassVersion(host.Version().String()), internal.CassHostID(host.HostID()), internal.CassHostState(host.State().String()), } return append(connectionLevelAttributes, values...) } // nanoToMilliseconds converts nanoseconds to milliseconds. func nanoToMilliseconds(ns int64) int64 { return ns / int64(time.Millisecond) } test/000077500000000000000000000000001443314701600342305ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocqldoc.go000066400000000000000000000017011443314701600353230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelgocql instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/test" go.mod000066400000000000000000000021101443314701600353300ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/test go 1.19 require ( github.com/gocql/gocql v1.4.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib v1.17.0 go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql => ../ replace go.opentelemetry.io/contrib => ../../../../../../ go.sum000066400000000000000000000102511443314701600353620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/testgithub.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gocql/gocql v1.4.0 h1:NIlXAJXsjzjGvVn36njh9OLYWzS3D7FdvsifLj4eDEY= github.com/gocql/gocql v1.4.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gocql_test.go000066400000000000000000000351631443314701600367330ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "fmt" "log" "os" "testing" "time" "github.com/gocql/gocql" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/internal" "go.opentelemetry.io/contrib/internal/util" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) const ( keyspace string = "gotest" tableName string = "test_table" ) type mockConnectObserver struct { callCount int } func (m *mockConnectObserver) ObserveConnect(observedConnect gocql.ObservedConnect) { m.callCount++ } func TestQuery(t *testing.T) { defer afterEach(t) cluster := getCluster() sr := tracetest.NewSpanRecorder() tracerProvider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) reader := metric.NewManualReader() meterProvider := metric.NewMeterProvider(metric.WithReader(reader)) ctx, parentSpan := tracerProvider.Tracer(internal.InstrumentationName).Start(context.Background(), "gocql-test") session, err := otelgocql.NewSessionWithTracing( ctx, cluster, otelgocql.WithTracerProvider(tracerProvider), otelgocql.WithMeterProvider(meterProvider), otelgocql.WithConnectInstrumentation(false), ) require.NoError(t, err) defer session.Close() require.NoError(t, session.AwaitSchemaAgreement(ctx)) id := gocql.TimeUUID() title := "example-title" insertStmt := fmt.Sprintf("insert into %s (id, title) values (?, ?)", tableName) query := session.Query(insertStmt, id, title).WithContext(ctx) assert.NotNil(t, query, "expected query to not be nil") require.NoError(t, query.Exec()) parentSpan.End() // Get the spans and ensure that they are child spans to the local parent spans := sr.Ended() // Collect all the connection spans // total spans: // 1 span for the Query // 1 span created in test require.Len(t, spans, 2) // Verify attributes are correctly added to the spans. Omit the one local span for _, span := range spans[0 : len(spans)-1] { switch span.Name() { case insertStmt: assert.Contains(t, span.Attributes(), semconv.DBStatement(insertStmt)) assert.Equal(t, parentSpan.SpanContext().SpanID().String(), span.Parent().SpanID().String()) default: t.Fatalf("unexpected span name %s", span.Name()) } assertConnectionLevelAttributes(t, span) } rm := metricdata.ResourceMetrics{} err = reader.Collect(context.Background(), &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) sm := rm.ScopeMetrics[0] assertScope(t, sm) assertQueriesMetric(t, 1, insertStmt, requireMetric(t, "db.cassandra.queries", sm.Metrics)) assertRowsMetric(t, 1, requireMetric(t, "db.cassandra.rows", sm.Metrics)) assertLatencyMetric(t, 1, requireMetric(t, "db.cassandra.latency", sm.Metrics)) } func TestBatch(t *testing.T) { defer afterEach(t) cluster := getCluster() sr := tracetest.NewSpanRecorder() tracerProvider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) reader := metric.NewManualReader() meterProvider := metric.NewMeterProvider(metric.WithReader(reader)) ctx, parentSpan := tracerProvider.Tracer(internal.InstrumentationName).Start(context.Background(), "gocql-test") session, err := otelgocql.NewSessionWithTracing( ctx, cluster, otelgocql.WithTracerProvider(tracerProvider), otelgocql.WithMeterProvider(meterProvider), otelgocql.WithConnectInstrumentation(false), ) require.NoError(t, err) defer session.Close() require.NoError(t, session.AwaitSchemaAgreement(ctx)) batch := session.NewBatch(gocql.LoggedBatch).WithContext(ctx) for i := 0; i < 10; i++ { id := gocql.TimeUUID() title := fmt.Sprintf("batch-title-%d", i) stmt := fmt.Sprintf("insert into %s (id, title) values (?, ?)", tableName) batch.Query(stmt, id, title) } require.NoError(t, session.ExecuteBatch(batch)) parentSpan.End() spans := sr.Ended() // total spans: // 1 span for the query // 1 span for the local span if assert.Len(t, spans, 2) { span := spans[0] assert.Equal(t, internal.CassBatchQueryName, span.Name()) assert.Equal(t, parentSpan.SpanContext().SpanID(), span.Parent().SpanID()) assert.Contains(t, span.Attributes(), semconv.DBOperation("db.cassandra.batch.query")) assertConnectionLevelAttributes(t, span) } rm := metricdata.ResourceMetrics{} err = reader.Collect(context.Background(), &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) sm := rm.ScopeMetrics[0] assertScope(t, sm) assertBatchQueriesMetric(t, 1, requireMetric(t, "db.cassandra.batch.queries", sm.Metrics)) assertLatencyMetric(t, 1, requireMetric(t, "db.cassandra.latency", sm.Metrics)) } func TestConnection(t *testing.T) { defer afterEach(t) cluster := getCluster() sr := tracetest.NewSpanRecorder() tracerProvider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) reader := metric.NewManualReader() meterProvider := metric.NewMeterProvider(metric.WithReader(reader)) connectObserver := &mockConnectObserver{0} ctx := context.Background() session, err := otelgocql.NewSessionWithTracing( ctx, cluster, otelgocql.WithTracerProvider(tracerProvider), otelgocql.WithMeterProvider(meterProvider), otelgocql.WithConnectObserver(connectObserver), ) require.NoError(t, err) defer session.Close() require.NoError(t, session.AwaitSchemaAgreement(ctx)) spans := sr.Ended() assert.Less(t, 0, connectObserver.callCount) // Verify the span attributes for _, span := range spans { assert.Equal(t, internal.CassConnectName, span.Name()) assert.Contains(t, span.Attributes(), semconv.DBOperation("db.cassandra.connect")) assertConnectionLevelAttributes(t, span) } rm := metricdata.ResourceMetrics{} err = reader.Collect(context.Background(), &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) sm := rm.ScopeMetrics[0] assertScope(t, sm) assertConnectionsMetric(t, requireMetric(t, "db.cassandra.connections", sm.Metrics)) } func TestHostOrIP(t *testing.T) { hostAndPort := "127.0.0.1:9042" attr := internal.HostOrIP(hostAndPort) assert.Equal(t, semconv.NetSockPeerAddrKey, attr.Key) assert.Equal(t, "127.0.0.1", attr.Value.AsString()) hostAndPort = "exampleHost:9042" attr = internal.HostOrIP(hostAndPort) assert.Equal(t, semconv.NetPeerNameKey, attr.Key) assert.Equal(t, "exampleHost", attr.Value.AsString()) hostAndPort = "invalid-host-and-port-string" attr = internal.HostOrIP(hostAndPort) require.Empty(t, attr.Value.AsString()) } func assertConnectionLevelAttributes(t *testing.T, span sdktrace.ReadOnlySpan) { attrs := span.Attributes() assert.Contains(t, attrs, semconv.DBSystemCassandra) assert.Contains(t, attrs, semconv.NetSockPeerAddr("127.0.0.1")) assert.Contains(t, attrs, semconv.NetPeerPort(9042)) assert.Contains(t, attrs, internal.CassHostStateKey.String("UP")) assert.Equal(t, trace.SpanKindClient, span.SpanKind()) keys := make(map[attribute.Key]struct{}, len(attrs)) for _, a := range attrs { keys[a.Key] = struct{}{} } assert.Contains(t, keys, internal.CassVersionKey) assert.Contains(t, keys, internal.CassHostIDKey) } // getCluster creates a gocql ClusterConfig with the appropriate // settings for test cases. func getCluster() *gocql.ClusterConfig { cluster := gocql.NewCluster("127.0.0.1") cluster.Keyspace = keyspace cluster.Consistency = gocql.LocalQuorum cluster.NumConns = 1 return cluster } func assertScope(t *testing.T, sm metricdata.ScopeMetrics) { assert.Equal(t, instrumentation.Scope{ Name: "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql", Version: otelgocql.Version(), }, sm.Scope) } func requireMetric(t *testing.T, name string, metrics []metricdata.Metrics) metricdata.Metrics { m, ok := getMetric(name, metrics) require.Truef(t, ok, "missing metric %q", name) return m } func getMetric(name string, metrics []metricdata.Metrics) (metricdata.Metrics, bool) { for _, m := range metrics { if m.Name == name { return m, true } } return metricdata.Metrics{}, false } func assertQueriesMetric(t *testing.T, value int64, stmt string, m metricdata.Metrics) { assert.Equal(t, "db.cassandra.queries", m.Name) assert.Equal(t, "Number queries executed", m.Description) require.IsType(t, m.Data, metricdata.Sum[int64]{}) data := m.Data.(metricdata.Sum[int64]) assert.Equal(t, metricdata.CumulativeTemporality, data.Temporality, "Temporality") assert.True(t, data.IsMonotonic, "IsMonotonic") require.Len(t, data.DataPoints, 1, "DataPoints") dPt := data.DataPoints[0] assert.Equal(t, value, dPt.Value, "Value") assertAttrSet(t, []attribute.KeyValue{ internal.CassDBSystem(), internal.CassPeerIP("127.0.0.1"), internal.CassPeerPort(9042), internal.CassVersion("3"), internal.CassHostID("test-id"), internal.CassHostState("UP"), internal.CassKeyspace(keyspace), internal.CassStatement(stmt), }, dPt.Attributes) } func assertBatchQueriesMetric(t *testing.T, value int64, m metricdata.Metrics) { assert.Equal(t, "db.cassandra.batch.queries", m.Name) assert.Equal(t, "Number of batch queries executed", m.Description) require.IsType(t, m.Data, metricdata.Sum[int64]{}) data := m.Data.(metricdata.Sum[int64]) assert.Equal(t, metricdata.CumulativeTemporality, data.Temporality, "Temporality") assert.True(t, data.IsMonotonic, "IsMonotonic") require.Len(t, data.DataPoints, 1, "DataPoints") dPt := data.DataPoints[0] assert.Equal(t, value, dPt.Value, "Value") assertAttrSet(t, []attribute.KeyValue{ internal.CassDBSystem(), internal.CassPeerIP("127.0.0.1"), internal.CassPeerPort(9042), internal.CassVersion("3"), internal.CassHostID("test-id"), internal.CassHostState("UP"), internal.CassKeyspace(keyspace), }, dPt.Attributes) } func assertConnectionsMetric(t *testing.T, m metricdata.Metrics) { assert.Equal(t, "db.cassandra.connections", m.Name) assert.Equal(t, "Number of connections created", m.Description) require.IsType(t, m.Data, metricdata.Sum[int64]{}) data := m.Data.(metricdata.Sum[int64]) assert.Equal(t, metricdata.CumulativeTemporality, data.Temporality, "Temporality") assert.True(t, data.IsMonotonic, "IsMonotonic") for _, dPt := range data.DataPoints { assertAttrSet(t, []attribute.KeyValue{ internal.CassDBSystem(), internal.CassPeerIP("127.0.0.1"), internal.CassPeerPort(9042), internal.CassVersion("3"), internal.CassHostID("test-id"), internal.CassHostState("UP"), }, dPt.Attributes) } } func assertRowsMetric(t *testing.T, count uint64, m metricdata.Metrics) { assert.Equal(t, "db.cassandra.rows", m.Name) assert.Equal(t, "Number of rows returned from query", m.Description) require.IsType(t, m.Data, metricdata.Histogram[int64]{}) data := m.Data.(metricdata.Histogram[int64]) assert.Equal(t, metricdata.CumulativeTemporality, data.Temporality, "Temporality") require.Len(t, data.DataPoints, 1, "DataPoints") dPt := data.DataPoints[0] assert.Equal(t, count, dPt.Count, "Count") assertAttrSet(t, []attribute.KeyValue{ internal.CassDBSystem(), internal.CassPeerIP("127.0.0.1"), internal.CassPeerPort(9042), internal.CassVersion("3"), internal.CassHostID("test-id"), internal.CassHostState("UP"), internal.CassKeyspace(keyspace), }, dPt.Attributes) } func assertLatencyMetric(t *testing.T, count uint64, m metricdata.Metrics) { assert.Equal(t, "db.cassandra.latency", m.Name) assert.Equal(t, "Sum of latency to host in milliseconds", m.Description) assert.Equal(t, "ms", m.Unit) require.IsType(t, m.Data, metricdata.Histogram[int64]{}) data := m.Data.(metricdata.Histogram[int64]) assert.Equal(t, metricdata.CumulativeTemporality, data.Temporality, "Temporality") require.Len(t, data.DataPoints, 1, "DataPoints") dPt := data.DataPoints[0] assert.Equal(t, count, dPt.Count, "Count") assertAttrSet(t, []attribute.KeyValue{ internal.CassDBSystem(), internal.CassPeerIP("127.0.0.1"), internal.CassPeerPort(9042), internal.CassVersion("3"), internal.CassHostID("test-id"), internal.CassHostState("UP"), internal.CassKeyspace(keyspace), }, dPt.Attributes) } func assertAttrSet(t *testing.T, want []attribute.KeyValue, got attribute.Set) { for _, attr := range want { actual, ok := got.Value(attr.Key) if !assert.Truef(t, ok, "missing attribute %s", attr.Key) { continue } switch attr.Key { case internal.CassHostIDKey, internal.CassVersionKey: // Host ID and Version will change between test runs. assert.NotEmpty(t, actual) default: assert.Equal(t, attr.Value, actual) } } } // beforeAll creates the testing keyspace and table if they do not already exist. func beforeAll() error { cluster := gocql.NewCluster("localhost") cluster.Consistency = gocql.LocalQuorum cluster.Keyspace = "system" session, err := cluster.CreateSession() if err != nil { return fmt.Errorf("failed to connect to database during beforeAll, %v", err) } err = session.Query( fmt.Sprintf( "create keyspace if not exists %s with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }", keyspace, ), ).Exec() if err != nil { return err } cluster.Keyspace = keyspace cluster.Timeout = time.Second * 2 session, err = cluster.CreateSession() if err != nil { return err } err = session.Query( fmt.Sprintf("create table if not exists %s(id UUID, title text, PRIMARY KEY(id))", tableName), ).Exec() if err != nil { return err } return nil } // afterEach truncates the table used for testing. func afterEach(t *testing.T) { cluster := gocql.NewCluster("localhost") cluster.Consistency = gocql.LocalQuorum cluster.Keyspace = keyspace cluster.Timeout = time.Second * 2 session, err := cluster.CreateSession() if err != nil { t.Fatalf("failed to connect to database during afterEach, %v", err) } if err = session.Query(fmt.Sprintf("truncate table %s", tableName)).Exec(); err != nil { t.Fatalf("failed to truncate table, %v", err) } } func TestMain(m *testing.M) { util.IntegrationShouldRun("test-gocql") if err := beforeAll(); err != nil { log.Fatal(err) } os.Exit(m.Run()) } version.go000066400000000000000000000020601443314701600362420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/test" // Version is the current release version of the gocql instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020441443314701600352650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gocql/gocql/otelgocql// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgocql // import "go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql" // Version is the current release version of the gocql instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/000077500000000000000000000000001443314701600305565ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/000077500000000000000000000000001443314701600313675ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/000077500000000000000000000000001443314701600330645ustar00rootroot00000000000000config.go000066400000000000000000000061241443314701600346040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmux // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" import ( "net/http" "go.opentelemetry.io/otel/propagation" oteltrace "go.opentelemetry.io/otel/trace" ) // config is used to configure the mux middleware. type config struct { TracerProvider oteltrace.TracerProvider Propagators propagation.TextMapPropagator spanNameFormatter func(string, *http.Request) string PublicEndpoint bool PublicEndpointFn func(*http.Request) bool } // Option specifies instrumentation configuration options. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithPublicEndpoint configures the Handler to link the span with an incoming // span context. If this option is not provided, then the association is a child // association instead of a link. func WithPublicEndpoint() Option { return optionFunc(func(c *config) { c.PublicEndpoint = true }) } // WithPublicEndpointFn runs with every request, and allows conditionnally // configuring the Handler to link the span with an incoming span context. If // this option is not provided or returns false, then the association is a // child association instead of a link. // Note: WithPublicEndpoint takes precedence over WithPublicEndpointFn. func WithPublicEndpointFn(fn func(*http.Request) bool) Option { return optionFunc(func(c *config) { c.PublicEndpointFn = fn }) } // WithPropagators specifies propagators to use for extracting // information from the HTTP requests. If none are specified, global // ones will be used. func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagators != nil { cfg.Propagators = propagators } }) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider oteltrace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithSpanNameFormatter specifies a function to use for generating a custom span // name. By default, the route name (path template or regexp) is used. The route // name is provided so you can use it in the span name without needing to // duplicate the logic for extracting it from the request. func WithSpanNameFormatter(fn func(routeName string, r *http.Request) string) Option { return optionFunc(func(cfg *config) { cfg.spanNameFormatter = fn }) } doc.go000066400000000000000000000015661443314701600341110ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelmux instruments the github.com/gorilla/mux package. // // Currently only the routing of a received message can be instrumented. To do // it, use the Middleware function. package otelmux // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" example/000077500000000000000000000000001443314701600344405ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmuxDockerfile000066400000000000000000000013771443314701600364420ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/gorilla/mux/otelmux/example FROM base AS mux-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000012731443314701600357220ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/example# gorilla/mux instrumentation example An HTTP server using gorilla/mux and instrumentation. The server has a `/users/{id:[0-9]+}` endpoint. The server generates span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `mux-server` and `mux-client` services to run the example: ```sh docker-compose up --detach mux-server mux-client ``` The `mux-client` service sends just one HTTP request to `mux-server` and then exits. View the span generated by `mux-server` in the logs: ```sh docker-compose logs mux-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000020411443314701600400720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: mux-client: image: golang:alpine networks: - example command: - "/bin/sh" - "-c" - "wget http://mux-server:8080/users/123 && cat 123" depends_on: - mux-server mux-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example networks: example: go.mod000066400000000000000000000013351443314701600355500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux => ../ require ( github.com/gorilla/mux v1.8.0 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000043041443314701600355740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/examplegithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server.go000066400000000000000000000044631443314701600363040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "fmt" "log" "net/http" "github.com/gorilla/mux" "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) var tracer = otel.Tracer("mux-server") func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() r := mux.NewRouter() r.Use(otelmux.Middleware("my-server")) r.HandleFunc("/users/{id:[0-9]+}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] name := getUser(r.Context(), id) reply := fmt.Sprintf("user %s (id %s)\n", name, id) _, _ = w.Write(([]byte)(reply)) })) http.Handle("/", r) _ = http.ListenAndServe(":8080", nil) } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func getUser(ctx context.Context, id string) string { _, span := tracer.Start(ctx, "getUser", oteltrace.WithAttributes(attribute.String("id", id))) defer span.End() if id == "123" { return "otelmux tester" } return "unknown" } go.mod000066400000000000000000000010721443314701600341130ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmuxmodule go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux go 1.19 require ( github.com/felixge/httpsnoop v1.0.3 github.com/gorilla/mux v1.8.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000043101443314701600341360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmuxgithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mux.go000066400000000000000000000116141443314701600341500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmux // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" import ( "fmt" "net/http" "sync" "github.com/felixge/httpsnoop" "github.com/gorilla/mux" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" "go.opentelemetry.io/otel/trace" ) const ( tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" ) // Middleware sets up a handler to start tracing the incoming // requests. The service parameter should describe the name of the // (virtual) server handling the request. func Middleware(service string, opts ...Option) mux.MiddlewareFunc { cfg := config{} for _, opt := range opts { opt.apply(&cfg) } if cfg.TracerProvider == nil { cfg.TracerProvider = otel.GetTracerProvider() } tracer := cfg.TracerProvider.Tracer( tracerName, trace.WithInstrumentationVersion(Version()), ) if cfg.Propagators == nil { cfg.Propagators = otel.GetTextMapPropagator() } if cfg.spanNameFormatter == nil { cfg.spanNameFormatter = defaultSpanNameFunc } return func(handler http.Handler) http.Handler { return traceware{ service: service, tracer: tracer, propagators: cfg.Propagators, handler: handler, spanNameFormatter: cfg.spanNameFormatter, publicEndpoint: cfg.PublicEndpoint, publicEndpointFn: cfg.PublicEndpointFn, } } } type traceware struct { service string tracer trace.Tracer propagators propagation.TextMapPropagator handler http.Handler spanNameFormatter func(string, *http.Request) string publicEndpoint bool publicEndpointFn func(*http.Request) bool } type recordingResponseWriter struct { writer http.ResponseWriter written bool status int } var rrwPool = &sync.Pool{ New: func() interface{} { return &recordingResponseWriter{} }, } func getRRW(writer http.ResponseWriter) *recordingResponseWriter { rrw := rrwPool.Get().(*recordingResponseWriter) rrw.written = false rrw.status = http.StatusOK rrw.writer = httpsnoop.Wrap(writer, httpsnoop.Hooks{ Write: func(next httpsnoop.WriteFunc) httpsnoop.WriteFunc { return func(b []byte) (int, error) { if !rrw.written { rrw.written = true } return next(b) } }, WriteHeader: func(next httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { return func(statusCode int) { if !rrw.written { rrw.written = true rrw.status = statusCode } next(statusCode) } }, }) return rrw } func putRRW(rrw *recordingResponseWriter) { rrw.writer = nil rrwPool.Put(rrw) } // defaultSpanNameFunc just reuses the route name as the span name. func defaultSpanNameFunc(routeName string, _ *http.Request) string { return routeName } // ServeHTTP implements the http.Handler interface. It does the actual // tracing of the request. func (tw traceware) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := tw.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) routeStr := "" route := mux.CurrentRoute(r) if route != nil { var err error routeStr, err = route.GetPathTemplate() if err != nil { routeStr, err = route.GetPathRegexp() if err != nil { routeStr = "" } } } opts := []trace.SpanStartOption{ trace.WithAttributes(httpconv.ServerRequest(tw.service, r)...), trace.WithSpanKind(trace.SpanKindServer), } if tw.publicEndpoint || (tw.publicEndpointFn != nil && tw.publicEndpointFn(r.WithContext(ctx))) { opts = append(opts, trace.WithNewRoot()) // Linking incoming span context if any for public endpoint. if s := trace.SpanContextFromContext(ctx); s.IsValid() && s.IsRemote() { opts = append(opts, trace.WithLinks(trace.Link{SpanContext: s})) } } if routeStr == "" { routeStr = fmt.Sprintf("HTTP %s route not found", r.Method) } else { rAttr := semconv.HTTPRoute(routeStr) opts = append(opts, trace.WithAttributes(rAttr)) } spanName := tw.spanNameFormatter(routeStr, r) ctx, span := tw.tracer.Start(ctx, spanName, opts...) defer span.End() r2 := r.WithContext(ctx) rrw := getRRW(w) defer putRRW(rrw) tw.handler.ServeHTTP(rrw.writer, r2) if rrw.status > 0 { span.SetAttributes(semconv.HTTPStatusCode(rrw.status)) } span.SetStatus(httpconv.ServerStatus(rrw.status)) } mux_test.go000066400000000000000000000112461443314701600352100ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmux import ( "bufio" "context" "io" "net" "net/http" "net/http/httptest" "testing" "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) var sc = trace.NewSpanContext(trace.SpanContextConfig{ TraceID: [16]byte{1}, SpanID: [8]byte{1}, Remote: true, TraceFlags: trace.FlagsSampled, }) func TestPassthroughSpanFromGlobalTracer(t *testing.T) { var called bool router := mux.NewRouter() router.Use(Middleware("foobar")) // The default global TracerProvider provides "pass through" spans for any // span context in the incoming request context. router.HandleFunc("/user/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true got := trace.SpanFromContext(r.Context()).SpanContext() assert.Equal(t, sc, got) w.WriteHeader(http.StatusOK) })) r := httptest.NewRequest("GET", "/user/123", nil) r = r.WithContext(trace.ContextWithRemoteSpanContext(context.Background(), sc)) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.True(t, called, "failed to run test") } func TestPropagationWithGlobalPropagators(t *testing.T) { defer func(p propagation.TextMapPropagator) { otel.SetTextMapPropagator(p) }(otel.GetTextMapPropagator()) prop := propagation.TraceContext{} otel.SetTextMapPropagator(prop) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc) otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) var called bool router := mux.NewRouter() router.Use(Middleware("foobar")) router.HandleFunc("/user/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true span := trace.SpanFromContext(r.Context()) assert.Equal(t, sc, span.SpanContext()) w.WriteHeader(http.StatusOK) })) router.ServeHTTP(w, r) assert.True(t, called, "failed to run test") } func TestPropagationWithCustomPropagators(t *testing.T) { prop := propagation.TraceContext{} r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r.Header)) var called bool router := mux.NewRouter() router.Use(Middleware("foobar", WithPropagators(prop))) router.HandleFunc("/user/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true span := trace.SpanFromContext(r.Context()) assert.Equal(t, sc, span.SpanContext()) w.WriteHeader(http.StatusOK) })) router.ServeHTTP(w, r) assert.True(t, called, "failed to run test") } type testResponseWriter struct { writer http.ResponseWriter } func (rw *testResponseWriter) Header() http.Header { return rw.writer.Header() } func (rw *testResponseWriter) Write(b []byte) (int, error) { return rw.writer.Write(b) } func (rw *testResponseWriter) WriteHeader(statusCode int) { rw.writer.WriteHeader(statusCode) } // implement Hijacker. func (rw *testResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return nil, nil, nil } // implement Pusher. func (rw *testResponseWriter) Push(target string, opts *http.PushOptions) error { return nil } // implement Flusher. func (rw *testResponseWriter) Flush() { } // implement io.ReaderFrom. func (rw *testResponseWriter) ReadFrom(r io.Reader) (n int64, err error) { return 0, nil } func TestResponseWriterInterfaces(t *testing.T) { // make sure the recordingResponseWriter preserves interfaces implemented by the wrapped writer router := mux.NewRouter() router.Use(Middleware("foobar")) router.HandleFunc("/user/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Implements(t, (*http.Hijacker)(nil), w) assert.Implements(t, (*http.Pusher)(nil), w) assert.Implements(t, (*http.Flusher)(nil), w) assert.Implements(t, (*io.ReaderFrom)(nil), w) w.WriteHeader(http.StatusOK) })) r := httptest.NewRequest("GET", "/user/123", nil) w := &testResponseWriter{ writer: httptest.NewRecorder(), } router.ServeHTTP(w, r) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/test/000077500000000000000000000000001443314701600340435ustar00rootroot00000000000000doc.go000066400000000000000000000016751443314701600350710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelmux instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/test" go.mod000066400000000000000000000015051443314701600350730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/test go 1.19 require ( github.com/gorilla/mux v1.8.0 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux => ../ go.sum000066400000000000000000000050201443314701600351140ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/testgithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mux_test.go000066400000000000000000000214371443314701600361720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "fmt" "net/http" "net/http/httptest" "testing" "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestCustomSpanNameFormatter(t *testing.T) { exporter := tracetest.NewInMemoryExporter() tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(exporter)) routeTpl := "/user/{id}" testdata := []struct { spanNameFormatter func(string, *http.Request) string expected string }{ {nil, routeTpl}, { func(string, *http.Request) string { return "custom" }, "custom", }, { func(name string, r *http.Request) string { return fmt.Sprintf("%s %s", r.Method, name) }, "GET " + routeTpl, }, } for i, d := range testdata { t.Run(fmt.Sprintf("%d_%s", i, d.expected), func(t *testing.T) { router := mux.NewRouter() router.Use(otelmux.Middleware( "foobar", otelmux.WithTracerProvider(tp), otelmux.WithSpanNameFormatter(d.spanNameFormatter), )) router.HandleFunc(routeTpl, func(w http.ResponseWriter, r *http.Request) {}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) spans := exporter.GetSpans() require.Len(t, spans, 1) assert.Equal(t, d.expected, spans[0].Name) exporter.Reset() }) } } func ok(w http.ResponseWriter, _ *http.Request) {} func notfound(w http.ResponseWriter, _ *http.Request) { http.Error(w, "not found", http.StatusNotFound) } func TestSDKIntegration(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) router := mux.NewRouter() router.Use(otelmux.Middleware("foobar", otelmux.WithTracerProvider(provider))) router.HandleFunc("/user/{id:[0-9]+}", ok) router.HandleFunc("/book/{title}", ok) r0 := httptest.NewRequest("GET", "/user/123", nil) r1 := httptest.NewRequest("GET", "/book/foo", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r0) router.ServeHTTP(w, r1) require.Len(t, sr.Ended(), 2) assertSpan(t, sr.Ended()[0], "/user/{id:[0-9]+}", trace.SpanKindServer, attribute.String("net.host.name", "foobar"), attribute.Int("http.status_code", http.StatusOK), attribute.String("http.method", "GET"), attribute.String("http.route", "/user/{id:[0-9]+}"), ) assertSpan(t, sr.Ended()[1], "/book/{title}", trace.SpanKindServer, attribute.String("net.host.name", "foobar"), attribute.Int("http.status_code", http.StatusOK), attribute.String("http.method", "GET"), attribute.String("http.route", "/book/{title}"), ) } func TestNotFoundIsNotError(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) router := mux.NewRouter() router.Use(otelmux.Middleware("foobar", otelmux.WithTracerProvider(provider))) router.HandleFunc("/does/not/exist", notfound) r0 := httptest.NewRequest("GET", "/does/not/exist", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r0) require.Len(t, sr.Ended(), 1) assertSpan(t, sr.Ended()[0], "/does/not/exist", trace.SpanKindServer, attribute.String("net.host.name", "foobar"), attribute.Int("http.status_code", http.StatusNotFound), attribute.String("http.method", "GET"), attribute.String("http.route", "/does/not/exist"), ) assert.Equal(t, sr.Ended()[0].Status().Code, codes.Unset) } func assertSpan(t *testing.T, span sdktrace.ReadOnlySpan, name string, kind trace.SpanKind, attrs ...attribute.KeyValue) { assert.Equal(t, name, span.Name()) assert.Equal(t, trace.SpanKindServer, span.SpanKind()) got := make(map[attribute.Key]attribute.Value, len(span.Attributes())) for _, a := range span.Attributes() { got[a.Key] = a.Value } for _, want := range attrs { if !assert.Contains(t, got, want.Key) { continue } assert.Equal(t, got[want.Key], want.Value) } } func TestWithPublicEndpoint(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) remoteSpan := trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, Remote: true, } prop := propagation.TraceContext{} router := mux.NewRouter() router.Use(otelmux.Middleware("foobar", otelmux.WithPublicEndpoint(), otelmux.WithPropagators(prop), otelmux.WithTracerProvider(provider), )) router.HandleFunc("/with/public/endpoint", func(w http.ResponseWriter, r *http.Request) { s := trace.SpanFromContext(r.Context()) sc := s.SpanContext() // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) }) r0 := httptest.NewRequest("GET", "/with/public/endpoint", nil) w := httptest.NewRecorder() sc := trace.NewSpanContext(remoteSpan) ctx := trace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r0.Header)) router.ServeHTTP(w, r0) assert.Equal(t, http.StatusOK, w.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, sr.ForceFlush(ctx)) done := sr.Ended() require.Len(t, done, 1) require.Len(t, done[0].Links(), 1, "should contain link") require.True(t, sc.Equal(done[0].Links()[0].SpanContext), "should link incoming span context") } func TestWithPublicEndpointFn(t *testing.T) { remoteSpan := trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, TraceFlags: trace.FlagsSampled, Remote: true, } prop := propagation.TraceContext{} testdata := []struct { name string fn func(*http.Request) bool handlerAssert func(*testing.T, trace.SpanContext) spansAssert func(*testing.T, trace.SpanContext, []sdktrace.ReadOnlySpan) }{ { name: "with the method returning true", fn: func(r *http.Request) bool { return true }, handlerAssert: func(t *testing.T, sc trace.SpanContext) { // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, sc trace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 1, "should contain link") require.True(t, sc.Equal(spans[0].Links()[0].SpanContext), "should link incoming span context") }, }, { name: "with the method returning false", fn: func(r *http.Request) bool { return false }, handlerAssert: func(t *testing.T, sc trace.SpanContext) { // Should have remote span as parent assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.Equal(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, _ trace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 0, "should not contain link") }, }, } for _, tt := range testdata { t.Run(tt.name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) router := mux.NewRouter() router.Use(otelmux.Middleware("foobar", otelmux.WithPublicEndpointFn(tt.fn), otelmux.WithPropagators(prop), otelmux.WithTracerProvider(provider), )) router.HandleFunc("/with/public/endpointfn", func(w http.ResponseWriter, r *http.Request) { s := trace.SpanFromContext(r.Context()) tt.handlerAssert(t, s.SpanContext()) }) r0 := httptest.NewRequest("GET", "/with/public/endpointfn", nil) w := httptest.NewRecorder() sc := trace.NewSpanContext(remoteSpan) ctx := trace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r0.Header)) router.ServeHTTP(w, r0) assert.Equal(t, http.StatusOK, w.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, sr.ForceFlush(ctx)) spans := sr.Ended() tt.spansAssert(t, sc, spans) }) } } version.go000066400000000000000000000020641443314701600360020ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/test" // Version is the current release version of the gorilla/mux instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020461443314701600350230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/gorilla/mux/otelmux// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmux // import "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" // Version is the current release version of the gorilla/mux instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/000077500000000000000000000000001443314701600307115ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/000077500000000000000000000000001443314701600316275ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/000077500000000000000000000000001443314701600334315ustar00rootroot00000000000000config.go000066400000000000000000000040311443314701600351440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelecho // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" import ( "github.com/labstack/echo/v4/middleware" "go.opentelemetry.io/otel/propagation" oteltrace "go.opentelemetry.io/otel/trace" ) // config is used to configure the mux middleware. type config struct { TracerProvider oteltrace.TracerProvider Propagators propagation.TextMapPropagator Skipper middleware.Skipper } // Option specifies instrumentation configuration options. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithPropagators specifies propagators to use for extracting // information from the HTTP requests. If none are specified, global // ones will be used. func WithPropagators(propagators propagation.TextMapPropagator) Option { return optionFunc(func(cfg *config) { if propagators != nil { cfg.Propagators = propagators } }) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider oteltrace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithSkipper specifies a skipper for allowing requests to skip generating spans. func WithSkipper(skipper middleware.Skipper) Option { return optionFunc(func(cfg *config) { cfg.Skipper = skipper }) } doc.go000066400000000000000000000016301443314701600344460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelecho instruments the labstack/echo package // (https://github.com/labstack/echo). // // Currently only the routing of a received message can be instrumented. To do // so, use the Middleware function. package otelecho // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" echo.go000066400000000000000000000061561443314701600346270ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelecho // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" import ( "fmt" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" oteltrace "go.opentelemetry.io/otel/trace" ) const ( tracerKey = "otel-go-contrib-tracer-labstack-echo" tracerName = "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" ) // Middleware returns echo middleware which will trace incoming requests. func Middleware(service string, opts ...Option) echo.MiddlewareFunc { cfg := config{} for _, opt := range opts { opt.apply(&cfg) } if cfg.TracerProvider == nil { cfg.TracerProvider = otel.GetTracerProvider() } tracer := cfg.TracerProvider.Tracer( tracerName, oteltrace.WithInstrumentationVersion(Version()), ) if cfg.Propagators == nil { cfg.Propagators = otel.GetTextMapPropagator() } if cfg.Skipper == nil { cfg.Skipper = middleware.DefaultSkipper } return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { if cfg.Skipper(c) { return next(c) } c.Set(tracerKey, tracer) request := c.Request() savedCtx := request.Context() defer func() { request = request.WithContext(savedCtx) c.SetRequest(request) }() ctx := cfg.Propagators.Extract(savedCtx, propagation.HeaderCarrier(request.Header)) opts := []oteltrace.SpanStartOption{ oteltrace.WithAttributes(httpconv.ServerRequest(service, request)...), oteltrace.WithSpanKind(oteltrace.SpanKindServer), } if path := c.Path(); path != "" { rAttr := semconv.HTTPRoute(path) opts = append(opts, oteltrace.WithAttributes(rAttr)) } spanName := c.Path() if spanName == "" { spanName = fmt.Sprintf("HTTP %s route not found", request.Method) } ctx, span := tracer.Start(ctx, spanName, opts...) defer span.End() // pass the span through the request context c.SetRequest(request.WithContext(ctx)) // serve the request to the next middleware err := next(c) if err != nil { span.SetAttributes(attribute.String("echo.error", err.Error())) // invokes the registered HTTP error handler c.Error(err) } status := c.Response().Status span.SetStatus(httpconv.ServerStatus(status)) if status > 0 { span.SetAttributes(semconv.HTTPStatusCode(status)) } return err } } } echo_test.go000066400000000000000000000103401443314701600356540ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace_test.go package otelecho import ( "context" "net/http" "net/http/httptest" "testing" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" b3prop "go.opentelemetry.io/contrib/propagators/b3" ) func TestGetSpanNotInstrumented(t *testing.T) { router := echo.New() router.GET("/ping", func(c echo.Context) error { // Assert we don't have a span on the context. span := trace.SpanFromContext(c.Request().Context()) ok := !span.SpanContext().IsValid() assert.True(t, ok) return c.String(http.StatusOK, "ok") }) r := httptest.NewRequest("GET", "/ping", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) response := w.Result() assert.Equal(t, http.StatusOK, response.StatusCode) } func TestPropagationWithGlobalPropagators(t *testing.T) { provider := trace.NewNoopTracerProvider() otel.SetTextMapPropagator(propagation.TraceContext{}) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) router := echo.New() router.Use(Middleware("foobar", WithTracerProvider(provider))) router.GET("/user/:id", func(c echo.Context) error { span := trace.SpanFromContext(c.Request().Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) return c.NoContent(http.StatusOK) }) router.ServeHTTP(w, r) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator()) assert.Equal(t, http.StatusOK, w.Result().StatusCode, "should call the 'user' handler") } func TestPropagationWithCustomPropagators(t *testing.T) { provider := trace.NewNoopTracerProvider() b3 := b3prop.New() r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = provider.Tracer(tracerName).Start(ctx, "test") b3.Inject(ctx, propagation.HeaderCarrier(r.Header)) router := echo.New() router.Use(Middleware("foobar", WithTracerProvider(provider), WithPropagators(b3))) router.GET("/user/:id", func(c echo.Context) error { span := trace.SpanFromContext(c.Request().Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) return c.NoContent(http.StatusOK) }) router.ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Result().StatusCode, "should call the 'user' handler") } func TestSkipper(t *testing.T) { r := httptest.NewRequest("GET", "/ping", nil) w := httptest.NewRecorder() skipper := func(c echo.Context) bool { return c.Request().RequestURI == "/ping" } router := echo.New() router.Use(Middleware("foobar", WithSkipper(skipper))) router.GET("/ping", func(c echo.Context) error { span := trace.SpanFromContext(c.Request().Context()) assert.False(t, span.SpanContext().HasSpanID()) assert.False(t, span.SpanContext().HasTraceID()) return c.NoContent(http.StatusOK) }) router.ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Result().StatusCode, "should call the 'ping' handler") } example/000077500000000000000000000000001443314701600350055ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelechoDockerfile000066400000000000000000000014031443314701600367750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/github.com/labstack/echo/otelecho/example FROM base AS echo-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000012771443314701600362730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/example# labstack echo instrumentation example An HTTP server using labstack echo and instrumentation. The server has a `/users/:id` endpoint. The server generates span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `echo-server` and `echo-client` services to run the example: ```sh docker-compose up --detach echo-server echo-client ``` The `echo-client` service sends just one HTTP request to `echo-server` and then exits. View the span generated by `echo-server` in the logs: ```sh docker-compose logs echo-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` docker-compose.yml000066400000000000000000000020461443314701600404440ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: echo-client: image: golang:alpine networks: - example command: - "/bin/sh" - "-c" - "wget http://echo-server:8080/users/123 && cat 123" depends_on: - echo-server echo-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../../ ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example networks: example: go.mod000066400000000000000000000023411443314701600361130ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/examplemodule go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) require ( github.com/labstack/echo/v4 v4.10.2 go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect ) go.sum000066400000000000000000000123411443314701600361410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/examplegithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server.go000066400000000000000000000043451443314701600366500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "net/http" "github.com/labstack/echo/v4" "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) var tracer = otel.Tracer("echo-server") func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() r := echo.New() r.Use(otelecho.Middleware("my-server")) r.GET("/users/:id", func(c echo.Context) error { id := c.Param("id") name := getUser(c.Request().Context(), id) return c.JSON(http.StatusOK, struct { ID string Name string }{ ID: id, Name: name, }) }) _ = r.Start(":8080") } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func getUser(ctx context.Context, id string) string { _, span := tracer.Start(ctx, "getUser", oteltrace.WithAttributes(attribute.String("id", id))) defer span.End() if id == "123" { return "otelecho tester" } return "unknown" } go.mod000066400000000000000000000022351443314701600344620ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelechomodule go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho go 1.19 replace go.opentelemetry.io/contrib/propagators/b3 => ../../../../../propagators/b3 require ( github.com/labstack/echo/v4 v4.10.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000121331443314701600345050ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelechogithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= test/000077500000000000000000000000001443314701600343315ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelechodoc.go000066400000000000000000000017011443314701600354240ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelecho instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/test" echo_test.go000066400000000000000000000154111443314701600366370ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/DataDog/dd-trace-go/blob/8fb554ff7cf694267f9077ae35e27ce4689ed8b6/contrib/gin-gonic/gin/gintrace_test.go package test import ( "errors" "net/http" "net/http/httptest" "testing" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/attribute" oteltrace "go.opentelemetry.io/otel/trace" ) func TestChildSpanFromGlobalTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) otel.SetTracerProvider(provider) router := echo.New() router.Use(otelecho.Middleware("foobar")) router.GET("/user/:id", func(c echo.Context) error { return c.NoContent(http.StatusOK) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Result().StatusCode, "should call the 'user' handler") assert.Len(t, sr.Ended(), 1) } func TestChildSpanFromCustomTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) router := echo.New() router.Use(otelecho.Middleware("foobar", otelecho.WithTracerProvider(provider))) router.GET("/user/:id", func(c echo.Context) error { return c.NoContent(http.StatusOK) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Result().StatusCode, "should call the 'user' handler") assert.Len(t, sr.Ended(), 1) } func TestTrace200(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) router := echo.New() router.Use(otelecho.Middleware("foobar", otelecho.WithTracerProvider(provider))) router.GET("/user/:id", func(c echo.Context) error { id := c.Param("id") return c.String(http.StatusOK, id) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() // do and verify the request router.ServeHTTP(w, r) response := w.Result() require.Equal(t, http.StatusOK, response.StatusCode) // verify traces look good spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "/user/:id", span.Name()) assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) attrs := span.Attributes() assert.Contains(t, attrs, attribute.String("net.host.name", "foobar")) assert.Contains(t, attrs, attribute.Int("http.status_code", http.StatusOK)) assert.Contains(t, attrs, attribute.String("http.method", "GET")) assert.Contains(t, attrs, attribute.String("http.route", "/user/:id")) } func TestError(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) // setup router := echo.New() router.Use(otelecho.Middleware("foobar", otelecho.WithTracerProvider(provider))) wantErr := errors.New("oh no") // configure a handler that returns an error and 5xx status // code router.GET("/server_err", func(c echo.Context) error { return wantErr }) r := httptest.NewRequest("GET", "/server_err", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) response := w.Result() assert.Equal(t, http.StatusInternalServerError, response.StatusCode) // verify the errors and status are correct spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "/server_err", span.Name()) attrs := span.Attributes() assert.Contains(t, attrs, attribute.String("net.host.name", "foobar")) assert.Contains(t, attrs, attribute.Int("http.status_code", http.StatusInternalServerError)) assert.Contains(t, attrs, attribute.String("echo.error", "oh no")) // server errors set the status assert.Equal(t, codes.Error, span.Status().Code) } func TestStatusError(t *testing.T) { for _, tc := range []struct { name string echoError string statusCode int spanCode codes.Code handler func(c echo.Context) error }{ { name: "StandardError", echoError: "oh no", statusCode: http.StatusInternalServerError, spanCode: codes.Error, handler: func(c echo.Context) error { return errors.New("oh no") }, }, { name: "EchoHTTPServerError", echoError: "code=500, message=my error message", statusCode: http.StatusInternalServerError, spanCode: codes.Error, handler: func(c echo.Context) error { return echo.NewHTTPError(http.StatusInternalServerError, "my error message") }, }, { name: "EchoHTTPClientError", echoError: "code=400, message=my error message", statusCode: http.StatusBadRequest, spanCode: codes.Unset, handler: func(c echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, "my error message") }, }, } { t.Run(tc.name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) router := echo.New() router.Use(otelecho.Middleware("foobar", otelecho.WithTracerProvider(provider))) router.GET("/err", tc.handler) r := httptest.NewRequest("GET", "/err", nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) spans := sr.Ended() require.Len(t, spans, 1) span := spans[0] assert.Equal(t, "/err", span.Name()) assert.Equal(t, tc.spanCode, span.Status().Code) attrs := span.Attributes() assert.Contains(t, attrs, attribute.String("net.host.name", "foobar")) assert.Contains(t, attrs, attribute.String("http.route", "/err")) assert.Contains(t, attrs, attribute.String("http.method", "GET")) assert.Contains(t, attrs, attribute.Int("http.status_code", tc.statusCode)) assert.Contains(t, attrs, attribute.String("echo.error", tc.echoError)) }) } } func TestErrorNotSwallowedByMiddleware(t *testing.T) { e := echo.New() r := httptest.NewRequest(http.MethodGet, "/err", nil) w := httptest.NewRecorder() c := e.NewContext(r, w) h := otelecho.Middleware("foobar")(echo.HandlerFunc(func(c echo.Context) error { return assert.AnError })) err := h(c) assert.Equal(t, assert.AnError, err) } go.mod000066400000000000000000000025111443314701600354360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/testmodule go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/test go 1.19 require ( github.com/labstack/echo/v4 v4.10.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace ( go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../../propagators/b3 ) go.sum000066400000000000000000000124141443314701600354660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/testgithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020601443314701600363430ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/test" // Version is the current release version of the echo instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020431443314701600353650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/github.com/labstack/echo/otelecho// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelecho // import "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" // Version is the current release version of the echo instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/000077500000000000000000000000001443314701600277055ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/000077500000000000000000000000001443314701600323155ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/000077500000000000000000000000001443314701600334345ustar00rootroot00000000000000otelmongo/000077500000000000000000000000001443314701600353605ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongoconfig.go000066400000000000000000000044161443314701600371610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" ) const defaultTracerName = "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" // config is used to configure the mongo tracer. type config struct { TracerProvider trace.TracerProvider Tracer trace.Tracer CommandAttributeDisabled bool } // newConfig returns a config with all Options set. func newConfig(opts ...Option) config { cfg := config{ TracerProvider: otel.GetTracerProvider(), CommandAttributeDisabled: true, } for _, opt := range opts { opt.apply(&cfg) } cfg.Tracer = cfg.TracerProvider.Tracer( defaultTracerName, trace.WithInstrumentationVersion(Version()), ) return cfg } // Option specifies instrumentation configuration options. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithCommandAttributeDisabled specifies if the MongoDB command is added as an attribute to Spans or not. // This is disabled by default and the MongoDB command will not be added as an attribute // to Spans if this option is not provided. func WithCommandAttributeDisabled(disabled bool) Option { return optionFunc(func(cfg *config) { cfg.CommandAttributeDisabled = disabled }) } doc.go000066400000000000000000000023011443314701600364500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelmongo instruments go.mongodb.org/mongo-driver/mongo. // // This package is compatable with v0.2.0 of // go.mongodb.org/mongo-driver/mongo. // // `NewMonitor` will return an event.CommandMonitor which is used to trace // requests. // // This code was originally based on the following: // - https://github.com/DataDog/dd-trace-go/tree/02f0449efa3cb382d499fadc873957385dcb2192/contrib/go.mongodb.org/mongo-driver/mongo // - https://github.com/DataDog/dd-trace-go/tree/v1.23.3/ddtrace/ext package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" example_test.go000066400000000000000000000027361443314701600404110ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmongo_test import ( "context" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" ) func Example() { // connect to MongoDB opts := options.Client() opts.Monitor = otelmongo.NewMonitor() opts.ApplyURI("mongodb://localhost:27017") client, err := mongo.Connect(context.Background(), opts) if err != nil { panic(err) } db := client.Database("example") inventory := db.Collection("inventory") _, err = inventory.InsertOne(context.Background(), bson.D{ {Key: "item", Value: "canvas"}, {Key: "qty", Value: 100}, {Key: "attributes", Value: bson.A{"cotton"}}, {Key: "size", Value: bson.D{ {Key: "h", Value: 28}, {Key: "w", Value: 35.5}, {Key: "uom", Value: "cm"}, }}, }) if err != nil { panic(err) } } go.mod000066400000000000000000000016711443314701600364730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongomodule go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo go 1.19 require ( go.mongodb.org/mongo-driver v1.11.6 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/text v0.4.0 // indirect ) go.sum000066400000000000000000000136301443314701600365160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongogithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o= go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mongo.go000066400000000000000000000106061443314701600370310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" import ( "context" "fmt" "strconv" "strings" "sync" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/event" ) type spanKey struct { ConnectionID string RequestID int64 } type monitor struct { sync.Mutex spans map[spanKey]trace.Span cfg config } func (m *monitor) Started(ctx context.Context, evt *event.CommandStartedEvent) { var spanName string hostname, port := peerInfo(evt) attrs := []attribute.KeyValue{ semconv.DBSystemMongoDB, semconv.DBOperation(evt.CommandName), semconv.DBName(evt.DatabaseName), semconv.NetPeerName(hostname), semconv.NetPeerPort(port), semconv.NetTransportTCP, } if !m.cfg.CommandAttributeDisabled { attrs = append(attrs, semconv.DBStatement(sanitizeCommand(evt.Command))) } if collection, err := extractCollection(evt); err == nil && collection != "" { spanName = collection + "." attrs = append(attrs, semconv.DBMongoDBCollection(collection)) } spanName += evt.CommandName opts := []trace.SpanStartOption{ trace.WithSpanKind(trace.SpanKindClient), trace.WithAttributes(attrs...), } _, span := m.cfg.Tracer.Start(ctx, spanName, opts...) key := spanKey{ ConnectionID: evt.ConnectionID, RequestID: evt.RequestID, } m.Lock() m.spans[key] = span m.Unlock() } func (m *monitor) Succeeded(ctx context.Context, evt *event.CommandSucceededEvent) { m.Finished(&evt.CommandFinishedEvent, nil) } func (m *monitor) Failed(ctx context.Context, evt *event.CommandFailedEvent) { m.Finished(&evt.CommandFinishedEvent, fmt.Errorf("%s", evt.Failure)) } func (m *monitor) Finished(evt *event.CommandFinishedEvent, err error) { key := spanKey{ ConnectionID: evt.ConnectionID, RequestID: evt.RequestID, } m.Lock() span, ok := m.spans[key] if ok { delete(m.spans, key) } m.Unlock() if !ok { return } if err != nil { span.SetStatus(codes.Error, err.Error()) } span.End() } // TODO sanitize values where possible, then reenable `db.statement` span attributes default. // TODO limit maximum size. func sanitizeCommand(command bson.Raw) string { b, _ := bson.MarshalExtJSON(command, false, false) return string(b) } // extractCollection extracts the collection for the given mongodb command event. // For CRUD operations, this is the first key/value string pair in the bson // document where key == "" (e.g. key == "insert"). // For database meta-level operations, such a key may not exist. func extractCollection(evt *event.CommandStartedEvent) (string, error) { elt, err := evt.Command.IndexErr(0) if err != nil { return "", err } if key, err := elt.KeyErr(); err == nil && key == evt.CommandName { var v bson.RawValue if v, err = elt.ValueErr(); err != nil || v.Type != bsontype.String { return "", err } return v.StringValue(), nil } return "", fmt.Errorf("collection name not found") } // NewMonitor creates a new mongodb event CommandMonitor. func NewMonitor(opts ...Option) *event.CommandMonitor { cfg := newConfig(opts...) m := &monitor{ spans: make(map[spanKey]trace.Span), cfg: cfg, } return &event.CommandMonitor{ Started: m.Started, Succeeded: m.Succeeded, Failed: m.Failed, } } func peerInfo(evt *event.CommandStartedEvent) (hostname string, port int) { hostname = evt.ConnectionID port = 27017 if idx := strings.IndexByte(hostname, '['); idx >= 0 { hostname = hostname[:idx] } if idx := strings.IndexByte(hostname, ':'); idx >= 0 { port = func(p int, e error) int { return p }(strconv.Atoi(hostname[idx+1:])) hostname = hostname[:idx] } return hostname, port } test/000077500000000000000000000000001443314701600363375ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongodoc.go000066400000000000000000000017141443314701600374360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelmongo instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test" go.mod000066400000000000000000000027301443314701600374470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/testmodule go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test go 1.19 require ( github.com/stretchr/testify v1.8.3 go.mongodb.org/mongo-driver v1.11.6 go.opentelemetry.io/contrib v1.17.0 go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace ( go.opentelemetry.io/contrib => ../../../../../.. go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo => ../ ) go.sum000066400000000000000000000146371443314701600375050ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/testgithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o= go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mongo_test.go000066400000000000000000000200071443314701600410430ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "os" "testing" "time" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" "go.opentelemetry.io/contrib/internal/util" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestMain(m *testing.M) { util.IntegrationShouldRun("test-mongo-driver") os.Exit(m.Run()) } type validator func(sdktrace.ReadOnlySpan) bool func TestDBCrudOperation(t *testing.T) { commonValidators := []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.insert", s.Name(), "expected %s", s.Name()) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Contains(t, s.Attributes(), attribute.String("db.operation", "insert")) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Contains(t, s.Attributes(), attribute.String("db.mongodb.collection", "test-collection")) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, codes.Unset, s.Status().Code) }, } tt := []struct { title string operation func(context.Context, *mongo.Database) (interface{}, error) excludeCommand bool validators []validator }{ { title: "insert", operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, excludeCommand: false, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { if attr.Key == "db.statement" { return assert.Contains(t, attr.Value.AsString(), `"test-item":"test-value"`) } } return false }), }, { title: "insert", operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, excludeCommand: true, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { if attr.Key == "db.statement" { return false } } return true }), }, } for _, tc := range tt { title := tc.title if tc.excludeCommand { title = title + "/excludeCommand" } else { title = title + "/includeCommand" } t.Run(title, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) defer cancel() ctx, span := provider.Tracer("test").Start(ctx, "mongodb-test") addr := "mongodb://localhost:27017/?connect=direct" opts := options.Client() opts.Monitor = otelmongo.NewMonitor( otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(tc.excludeCommand), ) opts.ApplyURI(addr) client, err := mongo.Connect(ctx, opts) if err != nil { t.Fatal(err) } _, err = tc.operation(ctx, client.Database("test-database")) if err != nil { t.Error(err) } span.End() spans := sr.Ended() if !assert.Len(t, spans, 2, "expected 2 spans, received %d", len(spans)) { t.FailNow() } assert.Len(t, spans, 2) assert.Equal(t, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) assert.Equal(t, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) assert.Equal(t, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) s := spans[0] assert.Equal(t, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) assert.Contains(t, attrs, attribute.String("net.peer.name", "localhost")) assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) assert.Contains(t, attrs, attribute.String("db.name", "test-database")) for _, v := range tc.validators { assert.True(t, v(s)) } }) } } func TestDBCollectionAttribute(t *testing.T) { tt := []struct { title string operation func(context.Context, *mongo.Database) (interface{}, error) validators []validator }{ { title: "delete", operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").DeleteOne(ctx, bson.D{{Key: "test-item"}}) }, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.delete", s.Name()) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Contains(t, s.Attributes(), attribute.String("db.operation", "delete")) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Contains(t, s.Attributes(), attribute.String("db.mongodb.collection", "test-collection")) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, codes.Unset, s.Status().Code) }, }, }, { title: "listCollectionNames", operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.ListCollectionNames(ctx, bson.D{}) }, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "listCollections", s.Name()) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Contains(t, s.Attributes(), attribute.String("db.operation", "listCollections")) }, func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, codes.Unset, s.Status().Code) }, }, }, } for _, tc := range tt { t.Run(tc.title, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) defer cancel() ctx, span := provider.Tracer("test").Start(ctx, "mongodb-test") addr := "mongodb://localhost:27017/?connect=direct" opts := options.Client() opts.Monitor = otelmongo.NewMonitor( otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(true), ) opts.ApplyURI(addr) client, err := mongo.Connect(ctx, opts) if err != nil { t.Fatal(err) } _, err = tc.operation(ctx, client.Database("test-database")) if err != nil { t.Error(err) } span.End() spans := sr.Ended() if !assert.Len(t, spans, 2, "expected 2 spans, received %d", len(spans)) { t.FailNow() } assert.Len(t, spans, 2) assert.Equal(t, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) assert.Equal(t, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) assert.Equal(t, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) s := spans[0] assert.Equal(t, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) assert.Contains(t, attrs, attribute.String("net.peer.name", "localhost")) assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) assert.Contains(t, attrs, attribute.String("db.name", "test-database")) for _, v := range tc.validators { assert.True(t, v(s)) } }) } } version.go000066400000000000000000000021021443314701600403460ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test" // Version is the current release version of the mongo-driver instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020661443314701600374000ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmongo // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" // Version is the current release version of the mongo-driver instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/000077500000000000000000000000001443314701600303765ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/000077500000000000000000000000001443314701600313315ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/000077500000000000000000000000001443314701600331505ustar00rootroot00000000000000benchmark_test.go000066400000000000000000000056651443314701600364250ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc_test import ( "context" "net" "testing" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/interop" pb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel/trace" ) const bufSize = 2048 var tracerProvider = trace.NewNoopTracerProvider() func benchmark(b *testing.B, cOpt []grpc.DialOption, sOpt []grpc.ServerOption) { l := bufconn.Listen(bufSize) defer l.Close() s := grpc.NewServer(sOpt...) pb.RegisterTestServiceServer(s, interop.NewTestServer()) go func() { if err := s.Serve(l); err != nil { panic(err) } }() defer s.Stop() ctx := context.Background() dial := func(context.Context, string) (net.Conn, error) { return l.Dial() } conn, err := grpc.DialContext( ctx, "bufnet", append([]grpc.DialOption{ grpc.WithContextDialer(dial), grpc.WithTransportCredentials(insecure.NewCredentials()), }, cOpt...)..., ) if err != nil { b.Fatalf("Failed to dial bufnet: %v", err) } defer conn.Close() client := pb.NewTestServiceClient(conn) b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { interop.DoEmptyUnaryCall(client) interop.DoLargeUnaryCall(client) interop.DoClientStreaming(client) interop.DoServerStreaming(client) interop.DoPingPong(client) interop.DoEmptyStream(client) } b.StopTimer() } func BenchmarkNoInstrumentation(b *testing.B) { benchmark(b, nil, nil) } func BenchmarkUnaryServerInterceptor(b *testing.B) { benchmark(b, nil, []grpc.ServerOption{ grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor( otelgrpc.WithTracerProvider(tracerProvider), )), }) } func BenchmarkStreamServerInterceptor(b *testing.B) { benchmark(b, nil, []grpc.ServerOption{ grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor( otelgrpc.WithTracerProvider(tracerProvider), )), }) } func BenchmarkUnaryClientInterceptor(b *testing.B) { benchmark(b, []grpc.DialOption{ grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor( otelgrpc.WithTracerProvider(tracerProvider), )), }, nil) } func BenchmarkStreamClientInterceptor(b *testing.B) { benchmark(b, []grpc.DialOption{ grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor( otelgrpc.WithTracerProvider(tracerProvider), )), }, nil) } config.go000066400000000000000000000075231443314701600346740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) const ( // instrumentationName is the name of this instrumentation package. instrumentationName = "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" // GRPCStatusCodeKey is convention for numeric status code of a gRPC request. GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code") ) // Filter is a predicate used to determine whether a given request in // interceptor info should be traced. A Filter must return true if // the request should be traced. type Filter func(*InterceptorInfo) bool // config is a group of options for this instrumentation. type config struct { Filter Filter Propagators propagation.TextMapPropagator TracerProvider trace.TracerProvider MeterProvider metric.MeterProvider meter metric.Meter rpcServerDuration metric.Int64Histogram } // Option applies an option value for a config. type Option interface { apply(*config) } // newConfig returns a config configured with all the passed Options. func newConfig(opts []Option) *config { c := &config{ Propagators: otel.GetTextMapPropagator(), TracerProvider: otel.GetTracerProvider(), MeterProvider: otel.GetMeterProvider(), } for _, o := range opts { o.apply(c) } c.meter = c.MeterProvider.Meter( instrumentationName, metric.WithInstrumentationVersion(Version()), metric.WithSchemaURL(semconv.SchemaURL), ) var err error if c.rpcServerDuration, err = c.meter.Int64Histogram("rpc.server.duration", metric.WithUnit("ms")); err != nil { otel.Handle(err) } return c } type propagatorsOption struct{ p propagation.TextMapPropagator } func (o propagatorsOption) apply(c *config) { if o.p != nil { c.Propagators = o.p } } // WithPropagators returns an Option to use the Propagators when extracting // and injecting trace context from requests. func WithPropagators(p propagation.TextMapPropagator) Option { return propagatorsOption{p: p} } type tracerProviderOption struct{ tp trace.TracerProvider } func (o tracerProviderOption) apply(c *config) { if o.tp != nil { c.TracerProvider = o.tp } } // WithInterceptorFilter returns an Option to use the request filter. func WithInterceptorFilter(f Filter) Option { return interceptorFilterOption{f: f} } type interceptorFilterOption struct { f Filter } func (o interceptorFilterOption) apply(c *config) { if o.f != nil { c.Filter = o.f } } // WithTracerProvider returns an Option to use the TracerProvider when // creating a Tracer. func WithTracerProvider(tp trace.TracerProvider) Option { return tracerProviderOption{tp: tp} } type meterProviderOption struct{ mp metric.MeterProvider } func (o meterProviderOption) apply(c *config) { if o.mp != nil { c.MeterProvider = o.mp } } // WithMeterProvider returns an Option to use the MeterProvider when // creating a Meter. If this option is not provide the global MeterProvider will be used. func WithMeterProvider(mp metric.MeterProvider) Option { return meterProviderOption{mp: mp} } example/000077500000000000000000000000001443314701600345245ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpcREADME.md000066400000000000000000000005421443314701600360040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example# gRPC Tracing Example Traces client and server calls via interceptors. ### Compile .proto Only required if the service definition (.proto) changes. ```sh # protobuf v1.3.2 protoc -I api --go_out=plugins=grpc,paths=source_relative:./api api/hello-service.proto ``` ### Run server ```sh go run ./server ``` ### Run client ```sh go run ./client ```api/000077500000000000000000000000001443314701600352755ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/examplehello-service.pb.go000066400000000000000000000262411443314701600407720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example/api// Code generated by protoc-gen-go. DO NOT EDIT. // source: hello-service.proto /* Package api is a generated protocol buffer package. It is generated from these files: hello-service.proto It has these top-level messages: HelloRequest HelloResponse */ package api import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" import ( context "golang.org/x/net/context" grpc "google.golang.org/grpc" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type HelloRequest struct { Greeting string `protobuf:"bytes,1,opt,name=greeting" json:"greeting,omitempty"` } func (m *HelloRequest) Reset() { *m = HelloRequest{} } func (m *HelloRequest) String() string { return proto.CompactTextString(m) } func (*HelloRequest) ProtoMessage() {} func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (m *HelloRequest) GetGreeting() string { if m != nil { return m.Greeting } return "" } type HelloResponse struct { Reply string `protobuf:"bytes,1,opt,name=reply" json:"reply,omitempty"` } func (m *HelloResponse) Reset() { *m = HelloResponse{} } func (m *HelloResponse) String() string { return proto.CompactTextString(m) } func (*HelloResponse) ProtoMessage() {} func (*HelloResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } func (m *HelloResponse) GetReply() string { if m != nil { return m.Reply } return "" } func init() { proto.RegisterType((*HelloRequest)(nil), "api.HelloRequest") proto.RegisterType((*HelloResponse)(nil), "api.HelloResponse") } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 // Client API for HelloService service type HelloServiceClient interface { SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) SayHelloServerStream(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (HelloService_SayHelloServerStreamClient, error) SayHelloClientStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloClientStreamClient, error) SayHelloBidiStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloBidiStreamClient, error) } type helloServiceClient struct { cc *grpc.ClientConn } func NewHelloServiceClient(cc *grpc.ClientConn) HelloServiceClient { return &helloServiceClient{cc} } func (c *helloServiceClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { out := new(HelloResponse) err := grpc.Invoke(ctx, "/api.HelloService/SayHello", in, out, c.cc, opts...) if err != nil { return nil, err } return out, nil } func (c *helloServiceClient) SayHelloServerStream(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (HelloService_SayHelloServerStreamClient, error) { stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[0], c.cc, "/api.HelloService/SayHelloServerStream", opts...) if err != nil { return nil, err } x := &helloServiceSayHelloServerStreamClient{stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } if err := x.ClientStream.CloseSend(); err != nil { return nil, err } return x, nil } type HelloService_SayHelloServerStreamClient interface { Recv() (*HelloResponse, error) grpc.ClientStream } type helloServiceSayHelloServerStreamClient struct { grpc.ClientStream } func (x *helloServiceSayHelloServerStreamClient) Recv() (*HelloResponse, error) { m := new(HelloResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *helloServiceClient) SayHelloClientStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloClientStreamClient, error) { stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[1], c.cc, "/api.HelloService/SayHelloClientStream", opts...) if err != nil { return nil, err } x := &helloServiceSayHelloClientStreamClient{stream} return x, nil } type HelloService_SayHelloClientStreamClient interface { Send(*HelloRequest) error CloseAndRecv() (*HelloResponse, error) grpc.ClientStream } type helloServiceSayHelloClientStreamClient struct { grpc.ClientStream } func (x *helloServiceSayHelloClientStreamClient) Send(m *HelloRequest) error { return x.ClientStream.SendMsg(m) } func (x *helloServiceSayHelloClientStreamClient) CloseAndRecv() (*HelloResponse, error) { if err := x.ClientStream.CloseSend(); err != nil { return nil, err } m := new(HelloResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func (c *helloServiceClient) SayHelloBidiStream(ctx context.Context, opts ...grpc.CallOption) (HelloService_SayHelloBidiStreamClient, error) { stream, err := grpc.NewClientStream(ctx, &_HelloService_serviceDesc.Streams[2], c.cc, "/api.HelloService/SayHelloBidiStream", opts...) if err != nil { return nil, err } x := &helloServiceSayHelloBidiStreamClient{stream} return x, nil } type HelloService_SayHelloBidiStreamClient interface { Send(*HelloRequest) error Recv() (*HelloResponse, error) grpc.ClientStream } type helloServiceSayHelloBidiStreamClient struct { grpc.ClientStream } func (x *helloServiceSayHelloBidiStreamClient) Send(m *HelloRequest) error { return x.ClientStream.SendMsg(m) } func (x *helloServiceSayHelloBidiStreamClient) Recv() (*HelloResponse, error) { m := new(HelloResponse) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } // Server API for HelloService service type HelloServiceServer interface { SayHello(context.Context, *HelloRequest) (*HelloResponse, error) SayHelloServerStream(*HelloRequest, HelloService_SayHelloServerStreamServer) error SayHelloClientStream(HelloService_SayHelloClientStreamServer) error SayHelloBidiStream(HelloService_SayHelloBidiStreamServer) error } func RegisterHelloServiceServer(s *grpc.Server, srv HelloServiceServer) { s.RegisterService(&_HelloService_serviceDesc, srv) } func _HelloService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(HelloRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(HelloServiceServer).SayHello(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/api.HelloService/SayHello", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(HelloServiceServer).SayHello(ctx, req.(*HelloRequest)) } return interceptor(ctx, in, info, handler) } func _HelloService_SayHelloServerStream_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(HelloRequest) if err := stream.RecvMsg(m); err != nil { return err } return srv.(HelloServiceServer).SayHelloServerStream(m, &helloServiceSayHelloServerStreamServer{stream}) } type HelloService_SayHelloServerStreamServer interface { Send(*HelloResponse) error grpc.ServerStream } type helloServiceSayHelloServerStreamServer struct { grpc.ServerStream } func (x *helloServiceSayHelloServerStreamServer) Send(m *HelloResponse) error { return x.ServerStream.SendMsg(m) } func _HelloService_SayHelloClientStream_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(HelloServiceServer).SayHelloClientStream(&helloServiceSayHelloClientStreamServer{stream}) } type HelloService_SayHelloClientStreamServer interface { SendAndClose(*HelloResponse) error Recv() (*HelloRequest, error) grpc.ServerStream } type helloServiceSayHelloClientStreamServer struct { grpc.ServerStream } func (x *helloServiceSayHelloClientStreamServer) SendAndClose(m *HelloResponse) error { return x.ServerStream.SendMsg(m) } func (x *helloServiceSayHelloClientStreamServer) Recv() (*HelloRequest, error) { m := new(HelloRequest) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } func _HelloService_SayHelloBidiStream_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(HelloServiceServer).SayHelloBidiStream(&helloServiceSayHelloBidiStreamServer{stream}) } type HelloService_SayHelloBidiStreamServer interface { Send(*HelloResponse) error Recv() (*HelloRequest, error) grpc.ServerStream } type helloServiceSayHelloBidiStreamServer struct { grpc.ServerStream } func (x *helloServiceSayHelloBidiStreamServer) Send(m *HelloResponse) error { return x.ServerStream.SendMsg(m) } func (x *helloServiceSayHelloBidiStreamServer) Recv() (*HelloRequest, error) { m := new(HelloRequest) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } return m, nil } var _HelloService_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.HelloService", HandlerType: (*HelloServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "SayHello", Handler: _HelloService_SayHello_Handler, }, }, Streams: []grpc.StreamDesc{ { StreamName: "SayHelloServerStream", Handler: _HelloService_SayHelloServerStream_Handler, ServerStreams: true, }, { StreamName: "SayHelloClientStream", Handler: _HelloService_SayHelloClientStream_Handler, ClientStreams: true, }, { StreamName: "SayHelloBidiStream", Handler: _HelloService_SayHelloBidiStream_Handler, ServerStreams: true, ClientStreams: true, }, }, Metadata: "hello-service.proto", } func init() { proto.RegisterFile("hello-service.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ // 192 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xce, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x2d, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x4e, 0x2c, 0xc8, 0x54, 0xd2, 0xe2, 0xe2, 0xf1, 0x00, 0xc9, 0x05, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x49, 0x71, 0x71, 0xa4, 0x17, 0xa5, 0xa6, 0x96, 0x64, 0xe6, 0xa5, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xf9, 0x4a, 0xaa, 0x5c, 0xbc, 0x50, 0xb5, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xa9, 0x05, 0x39, 0x95, 0x50, 0x95, 0x10, 0x8e, 0x51, 0x0b, 0x13, 0xd4, 0xcc, 0x60, 0x88, 0x75, 0x42, 0x86, 0x5c, 0x1c, 0xc1, 0x89, 0x95, 0x60, 0x21, 0x21, 0x41, 0xbd, 0xc4, 0x82, 0x4c, 0x3d, 0x64, 0x2b, 0xa5, 0x84, 0x90, 0x85, 0xa0, 0x26, 0xdb, 0x73, 0x89, 0xc0, 0xb4, 0x80, 0x4c, 0x49, 0x2d, 0x0a, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0x25, 0x52, 0xbb, 0x01, 0x23, 0xb2, 0x01, 0xce, 0x39, 0x99, 0xa9, 0x79, 0x25, 0x24, 0x19, 0xa0, 0x01, 0x32, 0x40, 0x08, 0x66, 0x80, 0x53, 0x66, 0x4a, 0x26, 0x89, 0xda, 0x0d, 0x18, 0x93, 0xd8, 0xc0, 0xa1, 0x6c, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x0e, 0xd5, 0x1c, 0xd2, 0x7c, 0x01, 0x00, 0x00, } hello-service.proto000066400000000000000000000020151443314701600411210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example/api// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; package api; service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse); rpc SayHelloServerStream (HelloRequest) returns (stream HelloResponse); rpc SayHelloClientStream (stream HelloRequest) returns (HelloResponse); rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloResponse); } message HelloRequest { string greeting = 1; } message HelloResponse { string reply = 1; } client/000077500000000000000000000000001443314701600360025ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/examplemain.go000066400000000000000000000125361443314701600372640ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example/client// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "fmt" "io" "log" "time" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example/api" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example/config" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" ) func main() { tp, err := config.Init() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() var conn *grpc.ClientConn conn, err = grpc.Dial(":7777", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), ) if err != nil { log.Fatalf("did not connect: %s", err) } defer func() { _ = conn.Close() }() c := api.NewHelloServiceClient(conn) if err := callSayHello(c); err != nil { log.Fatal(err) } if err := callSayHelloClientStream(c); err != nil { log.Fatal(err) } if err := callSayHelloServerStream(c); err != nil { log.Fatal(err) } if err := callSayHelloBidiStream(c); err != nil { log.Fatal(err) } time.Sleep(10 * time.Millisecond) } func callSayHello(c api.HelloServiceClient) error { md := metadata.Pairs( "timestamp", time.Now().Format(time.StampNano), "client-id", "web-api-client-us-east-1", "user-id", "some-test-user-id", ) ctx := metadata.NewOutgoingContext(context.Background(), md) response, err := c.SayHello(ctx, &api.HelloRequest{Greeting: "World"}) if err != nil { return fmt.Errorf("calling SayHello: %w", err) } log.Printf("Response from server: %s", response.Reply) return nil } func callSayHelloClientStream(c api.HelloServiceClient) error { md := metadata.Pairs( "timestamp", time.Now().Format(time.StampNano), "client-id", "web-api-client-us-east-1", "user-id", "some-test-user-id", ) ctx := metadata.NewOutgoingContext(context.Background(), md) stream, err := c.SayHelloClientStream(ctx) if err != nil { return fmt.Errorf("opening SayHelloClientStream: %w", err) } for i := 0; i < 5; i++ { err := stream.Send(&api.HelloRequest{Greeting: "World"}) time.Sleep(time.Duration(i*50) * time.Millisecond) if err != nil { return fmt.Errorf("sending to SayHelloClientStream: %w", err) } } response, err := stream.CloseAndRecv() if err != nil { return fmt.Errorf("closing SayHelloClientStream: %w", err) } log.Printf("Response from server: %s", response.Reply) return nil } func callSayHelloServerStream(c api.HelloServiceClient) error { md := metadata.Pairs( "timestamp", time.Now().Format(time.StampNano), "client-id", "web-api-client-us-east-1", "user-id", "some-test-user-id", ) ctx := metadata.NewOutgoingContext(context.Background(), md) stream, err := c.SayHelloServerStream(ctx, &api.HelloRequest{Greeting: "World"}) if err != nil { return fmt.Errorf("opening SayHelloServerStream: %w", err) } for { response, err := stream.Recv() if err == io.EOF { break } else if err != nil { return fmt.Errorf("receiving from SayHelloServerStream: %w", err) } log.Printf("Response from server: %s", response.Reply) time.Sleep(50 * time.Millisecond) } return nil } func callSayHelloBidiStream(c api.HelloServiceClient) error { md := metadata.Pairs( "timestamp", time.Now().Format(time.StampNano), "client-id", "web-api-client-us-east-1", "user-id", "some-test-user-id", ) ctx := metadata.NewOutgoingContext(context.Background(), md) stream, err := c.SayHelloBidiStream(ctx) if err != nil { return fmt.Errorf("opening SayHelloBidiStream: %w", err) } serverClosed := make(chan struct{}) clientClosed := make(chan struct{}) go func() { for i := 0; i < 5; i++ { err := stream.Send(&api.HelloRequest{Greeting: "World"}) if err != nil { // nolint: revive // This acts as its own main func. log.Fatalf("Error when sending to SayHelloBidiStream: %s", err) } time.Sleep(50 * time.Millisecond) } err := stream.CloseSend() if err != nil { // nolint: revive // This acts as its own main func. log.Fatalf("Error when closing SayHelloBidiStream: %s", err) } clientClosed <- struct{}{} }() go func() { for { response, err := stream.Recv() if err == io.EOF { break } else if err != nil { // nolint: revive // This acts as its own main func. log.Fatalf("Error when receiving from SayHelloBidiStream: %s", err) } log.Printf("Response from server: %s", response.Reply) time.Sleep(50 * time.Millisecond) } serverClosed <- struct{}{} }() // Wait until client and server both closed the connection. <-clientClosed <-serverClosed return nil } config/000077500000000000000000000000001443314701600357715ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/exampleconfig.go000066400000000000000000000025721443314701600375730ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example/config// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package config // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example/config" import ( "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) // Init configures an OpenTelemetry exporter and trace provider. func Init() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } go.mod000066400000000000000000000016161443314701600356360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/examplemodule go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => ../ require ( github.com/golang/protobuf v1.5.3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 golang.org/x/net v0.10.0 google.golang.org/grpc v1.55.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/protobuf v1.30.0 // indirect ) go.sum000066400000000000000000000073671443314701600356740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/examplecloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server/000077500000000000000000000000001443314701600360325ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/examplemain.go000066400000000000000000000070751443314701600373160ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/example/server// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "fmt" "io" "log" "net" "time" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example/api" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example/config" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" ) const ( port = ":7777" ) var tracer = otel.Tracer("grpc-example") // server is used to implement api.HelloServiceServer. type server struct { api.HelloServiceServer } // SayHello implements api.HelloServiceServer. func (s *server) SayHello(ctx context.Context, in *api.HelloRequest) (*api.HelloResponse, error) { log.Printf("Received: %v\n", in.GetGreeting()) s.workHard(ctx) time.Sleep(50 * time.Millisecond) return &api.HelloResponse{Reply: "Hello " + in.Greeting}, nil } func (s *server) workHard(ctx context.Context) { _, span := tracer.Start(ctx, "workHard", trace.WithAttributes(attribute.String("extra.key", "extra.value"))) defer span.End() time.Sleep(50 * time.Millisecond) } func (s *server) SayHelloServerStream(in *api.HelloRequest, out api.HelloService_SayHelloServerStreamServer) error { log.Printf("Received: %v\n", in.GetGreeting()) for i := 0; i < 5; i++ { err := out.Send(&api.HelloResponse{Reply: "Hello " + in.Greeting}) if err != nil { return err } time.Sleep(time.Duration(i*50) * time.Millisecond) } return nil } func (s *server) SayHelloClientStream(stream api.HelloService_SayHelloClientStreamServer) error { i := 0 for { in, err := stream.Recv() if err == io.EOF { break } else if err != nil { log.Printf("Non EOF error: %v\n", err) return err } log.Printf("Received: %v\n", in.GetGreeting()) i++ } time.Sleep(50 * time.Millisecond) return stream.SendAndClose(&api.HelloResponse{Reply: fmt.Sprintf("Hello (%v times)", i)}) } func (s *server) SayHelloBidiStream(stream api.HelloService_SayHelloBidiStreamServer) error { for { in, err := stream.Recv() if err == io.EOF { break } else if err != nil { log.Printf("Non EOF error: %v\n", err) return err } time.Sleep(50 * time.Millisecond) log.Printf("Received: %v\n", in.GetGreeting()) err = stream.Send(&api.HelloResponse{Reply: "Hello " + in.Greeting}) if err != nil { return err } } return nil } func main() { tp, err := config.Init() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()), ) api.RegisterHelloServiceServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } example_interceptor_test.go000066400000000000000000000021551443314701600405330ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc import ( "google.golang.org/grpc" ) func ExampleStreamClientInterceptor() { _, _ = grpc.Dial("localhost", grpc.WithStreamInterceptor(StreamClientInterceptor())) } func ExampleUnaryClientInterceptor() { _, _ = grpc.Dial("localhost", grpc.WithUnaryInterceptor(UnaryClientInterceptor())) } func ExampleStreamServerInterceptor() { _ = grpc.NewServer(grpc.StreamInterceptor(StreamServerInterceptor())) } func ExampleUnaryServerInterceptor() { _ = grpc.NewServer(grpc.UnaryInterceptor(UnaryServerInterceptor())) } filters/000077500000000000000000000000001443314701600345415ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpcfilters.go000066400000000000000000000107561443314701600365510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/filters// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package filters // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters" import ( "path" "strings" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" ) type gRPCPath struct { service string method string } // splitFullMethod splits path defined in gRPC protocol // and returns as gRPCPath object that has divided service and method names // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md // If name is not FullMethod, returned gRPCPath has empty service field. func splitFullMethod(i *otelgrpc.InterceptorInfo) gRPCPath { var name string switch i.Type { case otelgrpc.UnaryServer: name = i.UnaryServerInfo.FullMethod case otelgrpc.StreamServer: name = i.StreamServerInfo.FullMethod case otelgrpc.UnaryClient, otelgrpc.StreamClient: name = i.Method default: name = i.Method } s, m := path.Split(name) if s != "" { s = path.Clean(s) s = strings.TrimLeft(s, "/") } return gRPCPath{ service: s, method: m, } } // Any takes a list of Filters and returns a Filter that // returns true if any Filter in the list returns true. func Any(fs ...otelgrpc.Filter) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { for _, f := range fs { if f(i) { return true } } return false } } // All takes a list of Filters and returns a Filter that // returns true only if all Filters in the list return true. func All(fs ...otelgrpc.Filter) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { for _, f := range fs { if !f(i) { return false } } return true } } // None takes a list of Filters and returns a Filter that returns // true only if none of the Filters in the list return true. func None(fs ...otelgrpc.Filter) otelgrpc.Filter { return Not(Any(fs...)) } // Not provides a convenience mechanism for inverting a Filter. func Not(f otelgrpc.Filter) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { return !f(i) } } // MethodName returns a Filter that returns true if the request's // method name matches the provided string n. func MethodName(n string) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { p := splitFullMethod(i) return p.method == n } } // MethodPrefix returns a Filter that returns true if the request's // method starts with the provided string pre. func MethodPrefix(pre string) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { p := splitFullMethod(i) return strings.HasPrefix(p.method, pre) } } // FullMethodName returns a Filter that returns true if the request's // full RPC method string, i.e. /package.service/method, starts with // the provided string n. func FullMethodName(n string) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { var fm string switch i.Type { case otelgrpc.UnaryClient, otelgrpc.StreamClient: fm = i.Method case otelgrpc.UnaryServer: fm = i.UnaryServerInfo.FullMethod case otelgrpc.StreamServer: fm = i.StreamServerInfo.FullMethod default: fm = i.Method } return fm == n } } // ServiceName returns a Filter that returns true if the request's // service name, i.e. package.service, matches s. func ServiceName(s string) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { p := splitFullMethod(i) return p.service == s } } // ServicePrefix returns a Filter that returns true if the request's // service name, i.e. package.service, starts with the provided string pre. func ServicePrefix(pre string) otelgrpc.Filter { return func(i *otelgrpc.InterceptorInfo) bool { p := splitFullMethod(i) return strings.HasPrefix(p.service, pre) } } // HealthCheck returns a Filter that returns true if the request's // service name is health check defined by gRPC Health Checking Protocol. // https://github.com/grpc/grpc/blob/master/doc/health-checking.md func HealthCheck() otelgrpc.Filter { return ServicePrefix("grpc.health.v1.Health") } filters_test.go000066400000000000000000000324451443314701600376070ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/filters// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package filters // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters" import ( "testing" "google.golang.org/grpc" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" ) type testCase struct { name string i *otelgrpc.InterceptorInfo f otelgrpc.Filter want bool } func dummyUnaryServerInfo(n string) *grpc.UnaryServerInfo { return &grpc.UnaryServerInfo{ FullMethod: n, } } func dummyStreamServerInfo(n string) *grpc.StreamServerInfo { return &grpc.StreamServerInfo{ FullMethod: n, } } func TestMethodName(t *testing.T) { const dummyFullMethodName = "/example.HelloService/Hello" tcs := []testCase{ { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: MethodName("Hello"), want: true, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.StreamClient}, f: MethodName("Hello"), want: true, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: MethodName("Hello"), want: true, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethodName), Type: otelgrpc.StreamServer}, f: MethodName("Hello"), want: true, }, { name: "unary client interceptor fail", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: MethodName("Goodbye"), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestMethodPrefix(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: MethodPrefix("Foobar"), want: true, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.StreamClient}, f: MethodPrefix("Foobar"), want: true, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: MethodPrefix("Foobar"), want: true, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethodName), Type: otelgrpc.StreamServer}, f: MethodPrefix("Foobar"), want: true, }, { name: "unary client interceptor fail", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: MethodPrefix("Barfoo"), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestFullMethodName(t *testing.T) { const dummyFullMethodName = "/example.HelloService/Hello" tcs := []testCase{ { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: FullMethodName(dummyFullMethodName), want: true, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.StreamClient}, f: FullMethodName(dummyFullMethodName), want: true, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: FullMethodName(dummyFullMethodName), want: true, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethodName), Type: otelgrpc.StreamServer}, f: FullMethodName(dummyFullMethodName), want: true, }, { name: "unary client interceptor fail", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: FullMethodName("/example.HelloService/Goodbye"), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestServiceName(t *testing.T) { const dummyFullMethodName = "/example.HelloService/Hello" tcs := []testCase{ { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: ServiceName("example.HelloService"), want: true, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.StreamClient}, f: ServiceName("example.HelloService"), want: true, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: ServiceName("example.HelloService"), want: true, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethodName), Type: otelgrpc.StreamServer}, f: ServiceName("example.HelloService"), want: true, }, { name: "unary client interceptor fail", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: ServiceName("opentelemetry.HelloService"), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestServicePrefix(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: ServicePrefix("example"), want: true, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.StreamClient}, f: ServicePrefix("example"), want: true, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: ServicePrefix("example"), want: true, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethodName), Type: otelgrpc.StreamServer}, f: ServicePrefix("example"), want: true, }, { name: "unary client interceptor fail", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: ServicePrefix("opentelemetry"), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestAny(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "unary client interceptor true && true", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: Any(MethodName("FoobarHello"), MethodPrefix("Foobar")), want: true, }, { name: "unary client interceptor false && true", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: Any(MethodName("Hello"), MethodPrefix("Foobar")), want: true, }, { name: "unary client interceptor false && false", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: Any(MethodName("Goodbye"), MethodPrefix("Barfoo")), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestAll(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "unary client interceptor true && true", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: All(MethodName("FoobarHello"), MethodPrefix("Foobar")), want: true, }, { name: "unary client interceptor true && false", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: All(MethodName("FoobarHello"), MethodPrefix("Barfoo")), want: false, }, { name: "unary client interceptor false && false", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: All(MethodName("FoobarGoodbye"), MethodPrefix("Barfoo")), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestNone(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "unary client interceptor true && true", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: None(MethodName("FoobarHello"), MethodPrefix("Foobar")), want: false, }, { name: "unary client interceptor true && false", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: None(MethodName("FoobarHello"), MethodPrefix("Barfoo")), want: false, }, { name: "unary client interceptor false && false", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: None(MethodName("FoobarGoodbye"), MethodPrefix("Barfoo")), want: true, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestNot(t *testing.T) { const dummyFullMethodName = "/example.HelloService/FoobarHello" tcs := []testCase{ { name: "methodname not", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: Not(MethodName("FoobarHello")), want: false, }, { name: "method prefix not", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethodName), Type: otelgrpc.UnaryServer}, f: Not(MethodPrefix("FoobarHello")), want: false, }, { name: "unary client interceptor not all(true && true)", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethodName, Type: otelgrpc.UnaryClient}, f: Not(All(MethodName("FoobarHello"), MethodPrefix("Foobar"))), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } func TestHealthCheck(t *testing.T) { const ( healthCheck = "/grpc.health.v1.Health/Check" dummyFullMethod = "/example.HelloService/FoobarHello" ) tcs := []testCase{ { name: "unary client interceptor healthcheck", i: &otelgrpc.InterceptorInfo{Method: healthCheck, Type: otelgrpc.UnaryClient}, f: HealthCheck(), want: true, }, { name: "stream client interceptor healthcheck", i: &otelgrpc.InterceptorInfo{Method: healthCheck, Type: otelgrpc.StreamClient}, f: HealthCheck(), want: true, }, { name: "unary server interceptor healthcheck", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(healthCheck), Type: otelgrpc.UnaryServer}, f: HealthCheck(), want: true, }, { name: "stream server interceptor healthcheck", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(healthCheck), Type: otelgrpc.StreamServer}, f: HealthCheck(), want: true, }, { name: "unary client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethod, Type: otelgrpc.UnaryClient}, f: HealthCheck(), want: false, }, { name: "stream client interceptor", i: &otelgrpc.InterceptorInfo{Method: dummyFullMethod, Type: otelgrpc.StreamClient}, f: HealthCheck(), want: false, }, { name: "unary server interceptor", i: &otelgrpc.InterceptorInfo{UnaryServerInfo: dummyUnaryServerInfo(dummyFullMethod), Type: otelgrpc.UnaryServer}, f: HealthCheck(), want: false, }, { name: "stream server interceptor", i: &otelgrpc.InterceptorInfo{StreamServerInfo: dummyStreamServerInfo(dummyFullMethod), Type: otelgrpc.StreamServer}, f: HealthCheck(), want: false, }, } for _, tc := range tcs { out := tc.f(tc.i) if tc.want != out { t.Errorf("test case '%v' failed, wanted %v but obtained %v", tc.name, tc.want, out) } } } go.mod000066400000000000000000000017341443314701600342040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpcmodule go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.30.0 ) require ( cloud.google.com/go/compute v1.18.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000115311443314701600342250ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpccloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= interceptor.go000066400000000000000000000315001443314701600357550ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" // gRPC tracing middleware // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md import ( "context" "io" "net" "strconv" "time" "google.golang.org/grpc" grpc_codes "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) type messageType attribute.KeyValue // Event adds an event of the messageType to the span associated with the // passed context with a message id. func (m messageType) Event(ctx context.Context, id int, _ interface{}) { span := trace.SpanFromContext(ctx) if !span.IsRecording() { return } span.AddEvent("message", trace.WithAttributes( attribute.KeyValue(m), RPCMessageIDKey.Int(id), )) } var ( messageSent = messageType(RPCMessageTypeSent) messageReceived = messageType(RPCMessageTypeReceived) ) // UnaryClientInterceptor returns a grpc.UnaryClientInterceptor suitable // for use in a grpc.Dial call. func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor { cfg := newConfig(opts) tracer := cfg.TracerProvider.Tracer( instrumentationName, trace.WithInstrumentationVersion(Version()), ) return func( ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, callOpts ...grpc.CallOption, ) error { i := &InterceptorInfo{ Method: method, Type: UnaryClient, } if cfg.Filter != nil && !cfg.Filter(i) { return invoker(ctx, method, req, reply, cc, callOpts...) } name, attr := spanInfo(method, cc.Target()) var span trace.Span ctx, span = tracer.Start( ctx, name, trace.WithSpanKind(trace.SpanKindClient), trace.WithAttributes(attr...), ) defer span.End() ctx = inject(ctx, cfg.Propagators) messageSent.Event(ctx, 1, req) err := invoker(ctx, method, req, reply, cc, callOpts...) messageReceived.Event(ctx, 1, reply) if err != nil { s, _ := status.FromError(err) span.SetStatus(codes.Error, s.Message()) span.SetAttributes(statusCodeAttr(s.Code())) } else { span.SetAttributes(statusCodeAttr(grpc_codes.OK)) } return err } } type streamEventType int type streamEvent struct { Type streamEventType Err error } const ( receiveEndEvent streamEventType = iota errorEvent ) // clientStream wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and // SendMsg method call. type clientStream struct { grpc.ClientStream desc *grpc.StreamDesc events chan streamEvent eventsDone chan struct{} finished chan error receivedMessageID int sentMessageID int } var _ = proto.Marshal func (w *clientStream) RecvMsg(m interface{}) error { err := w.ClientStream.RecvMsg(m) if err == nil && !w.desc.ServerStreams { w.sendStreamEvent(receiveEndEvent, nil) } else if err == io.EOF { w.sendStreamEvent(receiveEndEvent, nil) } else if err != nil { w.sendStreamEvent(errorEvent, err) } else { w.receivedMessageID++ messageReceived.Event(w.Context(), w.receivedMessageID, m) } return err } func (w *clientStream) SendMsg(m interface{}) error { err := w.ClientStream.SendMsg(m) w.sentMessageID++ messageSent.Event(w.Context(), w.sentMessageID, m) if err != nil { w.sendStreamEvent(errorEvent, err) } return err } func (w *clientStream) Header() (metadata.MD, error) { md, err := w.ClientStream.Header() if err != nil { w.sendStreamEvent(errorEvent, err) } return md, err } func (w *clientStream) CloseSend() error { err := w.ClientStream.CloseSend() if err != nil { w.sendStreamEvent(errorEvent, err) } return err } func wrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc) *clientStream { events := make(chan streamEvent) eventsDone := make(chan struct{}) finished := make(chan error) go func() { defer close(eventsDone) for { select { case event := <-events: switch event.Type { case receiveEndEvent: finished <- nil return case errorEvent: finished <- event.Err return } case <-ctx.Done(): finished <- ctx.Err() return } } }() return &clientStream{ ClientStream: s, desc: desc, events: events, eventsDone: eventsDone, finished: finished, } } func (w *clientStream) sendStreamEvent(eventType streamEventType, err error) { select { case <-w.eventsDone: case w.events <- streamEvent{Type: eventType, Err: err}: } } // StreamClientInterceptor returns a grpc.StreamClientInterceptor suitable // for use in a grpc.Dial call. func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor { cfg := newConfig(opts) tracer := cfg.TracerProvider.Tracer( instrumentationName, trace.WithInstrumentationVersion(Version()), ) return func( ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, callOpts ...grpc.CallOption, ) (grpc.ClientStream, error) { i := &InterceptorInfo{ Method: method, Type: StreamClient, } if cfg.Filter != nil && !cfg.Filter(i) { return streamer(ctx, desc, cc, method, callOpts...) } name, attr := spanInfo(method, cc.Target()) var span trace.Span ctx, span = tracer.Start( ctx, name, trace.WithSpanKind(trace.SpanKindClient), trace.WithAttributes(attr...), ) ctx = inject(ctx, cfg.Propagators) s, err := streamer(ctx, desc, cc, method, callOpts...) if err != nil { grpcStatus, _ := status.FromError(err) span.SetStatus(codes.Error, grpcStatus.Message()) span.SetAttributes(statusCodeAttr(grpcStatus.Code())) span.End() return s, err } stream := wrapClientStream(ctx, s, desc) go func() { err := <-stream.finished if err != nil { s, _ := status.FromError(err) span.SetStatus(codes.Error, s.Message()) span.SetAttributes(statusCodeAttr(s.Code())) } else { span.SetAttributes(statusCodeAttr(grpc_codes.OK)) } span.End() }() return stream, nil } } // UnaryServerInterceptor returns a grpc.UnaryServerInterceptor suitable // for use in a grpc.NewServer call. func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor { cfg := newConfig(opts) tracer := cfg.TracerProvider.Tracer( instrumentationName, trace.WithInstrumentationVersion(Version()), ) return func( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { i := &InterceptorInfo{ UnaryServerInfo: info, Type: UnaryServer, } if cfg.Filter != nil && !cfg.Filter(i) { return handler(ctx, req) } ctx = extract(ctx, cfg.Propagators) name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) ctx, span := tracer.Start( trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)), name, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attr...), ) defer span.End() messageReceived.Event(ctx, 1, req) var statusCode grpc_codes.Code defer func(t time.Time) { elapsedTime := time.Since(t) / time.Millisecond attr = append(attr, semconv.RPCGRPCStatusCodeKey.Int64(int64(statusCode))) o := metric.WithAttributes(attr...) cfg.rpcServerDuration.Record(ctx, int64(elapsedTime), o) }(time.Now()) resp, err := handler(ctx, req) if err != nil { s, _ := status.FromError(err) statusCode, msg := serverStatus(s) span.SetStatus(statusCode, msg) span.SetAttributes(statusCodeAttr(s.Code())) messageSent.Event(ctx, 1, s.Proto()) } else { statusCode = grpc_codes.OK span.SetAttributes(statusCodeAttr(grpc_codes.OK)) messageSent.Event(ctx, 1, resp) } return resp, err } } // serverStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and // SendMsg method call. type serverStream struct { grpc.ServerStream ctx context.Context receivedMessageID int sentMessageID int } func (w *serverStream) Context() context.Context { return w.ctx } func (w *serverStream) RecvMsg(m interface{}) error { err := w.ServerStream.RecvMsg(m) if err == nil { w.receivedMessageID++ messageReceived.Event(w.Context(), w.receivedMessageID, m) } return err } func (w *serverStream) SendMsg(m interface{}) error { err := w.ServerStream.SendMsg(m) w.sentMessageID++ messageSent.Event(w.Context(), w.sentMessageID, m) return err } func wrapServerStream(ctx context.Context, ss grpc.ServerStream) *serverStream { return &serverStream{ ServerStream: ss, ctx: ctx, } } // StreamServerInterceptor returns a grpc.StreamServerInterceptor suitable // for use in a grpc.NewServer call. func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { cfg := newConfig(opts) tracer := cfg.TracerProvider.Tracer( instrumentationName, trace.WithInstrumentationVersion(Version()), ) return func( srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler, ) error { ctx := ss.Context() i := &InterceptorInfo{ StreamServerInfo: info, Type: StreamServer, } if cfg.Filter != nil && !cfg.Filter(i) { return handler(srv, wrapServerStream(ctx, ss)) } ctx = extract(ctx, cfg.Propagators) name, attr := spanInfo(info.FullMethod, peerFromCtx(ctx)) ctx, span := tracer.Start( trace.ContextWithRemoteSpanContext(ctx, trace.SpanContextFromContext(ctx)), name, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attr...), ) defer span.End() err := handler(srv, wrapServerStream(ctx, ss)) if err != nil { s, _ := status.FromError(err) statusCode, msg := serverStatus(s) span.SetStatus(statusCode, msg) span.SetAttributes(statusCodeAttr(s.Code())) } else { span.SetAttributes(statusCodeAttr(grpc_codes.OK)) } return err } } // spanInfo returns a span name and all appropriate attributes from the gRPC // method and peer address. func spanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) { attrs := []attribute.KeyValue{RPCSystemGRPC} name, mAttrs := internal.ParseFullMethod(fullMethod) attrs = append(attrs, mAttrs...) attrs = append(attrs, peerAttr(peerAddress)...) return name, attrs } // peerAttr returns attributes about the peer address. func peerAttr(addr string) []attribute.KeyValue { host, p, err := net.SplitHostPort(addr) if err != nil { return []attribute.KeyValue(nil) } if host == "" { host = "127.0.0.1" } port, err := strconv.Atoi(p) if err != nil { return []attribute.KeyValue(nil) } var attr []attribute.KeyValue if ip := net.ParseIP(host); ip != nil { attr = []attribute.KeyValue{ semconv.NetSockPeerAddr(host), semconv.NetSockPeerPort(port), } } else { attr = []attribute.KeyValue{ semconv.NetPeerName(host), semconv.NetPeerPort(port), } } return attr } // peerFromCtx returns a peer address from a context, if one exists. func peerFromCtx(ctx context.Context) string { p, ok := peer.FromContext(ctx) if !ok { return "" } return p.Addr.String() } // statusCodeAttr returns status code attribute based on given gRPC code. func statusCodeAttr(c grpc_codes.Code) attribute.KeyValue { return GRPCStatusCodeKey.Int64(int64(c)) } // serverStatus returns a span status code and message for a given gRPC // status code. It maps specific gRPC status codes to a corresponding span // status code and message. This function is intended for use on the server // side of a gRPC connection. // // If the gRPC status code is Unknown, DeadlineExceeded, Unimplemented, // Internal, Unavailable, or DataLoss, it returns a span status code of Error // and the message from the gRPC status. Otherwise, it returns a span status // code of Unset and an empty message. func serverStatus(grpcStatus *status.Status) (codes.Code, string) { switch grpcStatus.Code() { case grpc_codes.Unknown, grpc_codes.DeadlineExceeded, grpc_codes.Unimplemented, grpc_codes.Internal, grpc_codes.Unavailable, grpc_codes.DataLoss: return codes.Error, grpcStatus.Message() default: return codes.Unset, "" } } interceptorinfo.go000066400000000000000000000034251443314701600366360ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" import ( "google.golang.org/grpc" ) // InterceptorType is the flag to define which gRPC interceptor // the InterceptorInfo object is. type InterceptorType uint8 const ( // UndefinedInterceptor is the type for the interceptor information that is not // well initialized or categorized to other types. UndefinedInterceptor InterceptorType = iota // UnaryClient is the type for grpc.UnaryClient interceptor. UnaryClient // StreamClient is the type for grpc.StreamClient interceptor. StreamClient // UnaryServer is the type for grpc.UnaryServer interceptor. UnaryServer // StreamServer is the type for grpc.StreamServer interceptor. StreamServer ) // InterceptorInfo is the union of some arguments to four types of // gRPC interceptors. type InterceptorInfo struct { // Method is method name registered to UnaryClient and StreamClient Method string // UnaryServerInfo is the metadata for UnaryServer UnaryServerInfo *grpc.UnaryServerInfo // StreamServerInfo if the metadata for StreamServer StreamServerInfo *grpc.StreamServerInfo // Type is the type for interceptor Type InterceptorType } internal/000077500000000000000000000000001443314701600347055ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpcparse.go000066400000000000000000000027111443314701600363470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/internal// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal" import ( "strings" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // ParseFullMethod returns a span name following the OpenTelemetry semantic // conventions as well as all applicable span attribute.KeyValue attributes based // on a gRPC's FullMethod. func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) { name := strings.TrimLeft(fullMethod, "/") service, method, found := strings.Cut(name, "/") if !found { // Invalid format, does not follow `/package.service/method`. return name, nil } var attrs []attribute.KeyValue if service != "" { attrs = append(attrs, semconv.RPCService(service)) } if method != "" { attrs = append(attrs, semconv.RPCMethod(method)) } return name, attrs } metadata_supplier.go000066400000000000000000000054341443314701600371310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" import ( "context" "google.golang.org/grpc/metadata" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) type metadataSupplier struct { metadata *metadata.MD } // assert that metadataSupplier implements the TextMapCarrier interface. var _ propagation.TextMapCarrier = &metadataSupplier{} func (s *metadataSupplier) Get(key string) string { values := s.metadata.Get(key) if len(values) == 0 { return "" } return values[0] } func (s *metadataSupplier) Set(key string, value string) { s.metadata.Set(key, value) } func (s *metadataSupplier) Keys() []string { out := make([]string, 0, len(*s.metadata)) for key := range *s.metadata { out = append(out, key) } return out } // Inject injects correlation context and span context into the gRPC // metadata object. This function is meant to be used on outgoing // requests. // Deprecated: Unnecessary public func. func Inject(ctx context.Context, md *metadata.MD, opts ...Option) { c := newConfig(opts) c.Propagators.Inject(ctx, &metadataSupplier{ metadata: md, }) } func inject(ctx context.Context, propagators propagation.TextMapPropagator) context.Context { md, ok := metadata.FromOutgoingContext(ctx) if !ok { md = metadata.MD{} } propagators.Inject(ctx, &metadataSupplier{ metadata: &md, }) return metadata.NewOutgoingContext(ctx, md) } // Extract returns the correlation context and span context that // another service encoded in the gRPC metadata object with Inject. // This function is meant to be used on incoming requests. // Deprecated: Unnecessary public func. func Extract(ctx context.Context, md *metadata.MD, opts ...Option) (baggage.Baggage, trace.SpanContext) { c := newConfig(opts) ctx = c.Propagators.Extract(ctx, &metadataSupplier{ metadata: md, }) return baggage.FromContext(ctx), trace.SpanContextFromContext(ctx) } func extract(ctx context.Context, propagators propagation.TextMapPropagator) context.Context { md, ok := metadata.FromIncomingContext(ctx) if !ok { md = metadata.MD{} } return propagators.Extract(ctx, &metadataSupplier{ metadata: &md, }) } metadata_supplier_test.go000066400000000000000000000017571443314701600401740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc import ( "testing" "github.com/stretchr/testify/assert" "google.golang.org/grpc/metadata" ) func TestMetadataSupplier(t *testing.T) { md := metadata.New(map[string]string{ "k1": "v1", }) ms := &metadataSupplier{&md} v1 := ms.Get("k1") assert.Equal(t, v1, "v1") ms.Set("k2", "v2") v1 = ms.Get("k1") v2 := ms.Get("k2") assert.Equal(t, v1, "v1") assert.Equal(t, v2, "v2") } semconv.go000066400000000000000000000035241443314701600350760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" import ( "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) // Semantic conventions for attribute keys for gRPC. const ( // Name of message transmitted or received. RPCNameKey = attribute.Key("name") // Type of message transmitted or received. RPCMessageTypeKey = attribute.Key("message.type") // Identifier of message transmitted or received. RPCMessageIDKey = attribute.Key("message.id") // The compressed size of the message transmitted or received in bytes. RPCMessageCompressedSizeKey = attribute.Key("message.compressed_size") // The uncompressed size of the message transmitted or received in // bytes. RPCMessageUncompressedSizeKey = attribute.Key("message.uncompressed_size") ) // Semantic conventions for common RPC attributes. var ( // Semantic convention for gRPC as the remoting system. RPCSystemGRPC = semconv.RPCSystemGRPC // Semantic convention for a message named message. RPCNameMessage = RPCNameKey.String("message") // Semantic conventions for RPC message types. RPCMessageTypeSent = RPCMessageTypeKey.String("SENT") RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED") ) test/000077500000000000000000000000001443314701600340505ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpcdoc.go000066400000000000000000000016771443314701600351570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelgrpc instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/test" go.mod000066400000000000000000000025131443314701600351570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/testmodule go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/test go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 go.uber.org/goleak v1.2.1 google.golang.org/grpc v1.55.0 ) require ( cloud.google.com/go/compute v1.18.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => ../ go.sum000066400000000000000000000132371443314701600352110ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/testcloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc_test.go000066400000000000000000000423321443314701600363750ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/interop" pb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) const bufSize = 2048 func doCalls(cOpt []grpc.DialOption, sOpt []grpc.ServerOption) error { l := bufconn.Listen(bufSize) defer l.Close() s := grpc.NewServer(sOpt...) pb.RegisterTestServiceServer(s, interop.NewTestServer()) go func() { if err := s.Serve(l); err != nil { panic(err) } }() defer s.Stop() ctx := context.Background() dial := func(context.Context, string) (net.Conn, error) { return l.Dial() } conn, err := grpc.DialContext( ctx, "bufnet", append([]grpc.DialOption{ grpc.WithContextDialer(dial), grpc.WithTransportCredentials(insecure.NewCredentials()), }, cOpt...)..., ) if err != nil { return err } defer conn.Close() client := pb.NewTestServiceClient(conn) interop.DoEmptyUnaryCall(client) interop.DoLargeUnaryCall(client) interop.DoClientStreaming(client) interop.DoServerStreaming(client) interop.DoPingPong(client) return nil } func TestInterceptors(t *testing.T) { clientUnarySR := tracetest.NewSpanRecorder() clientUnaryTP := trace.NewTracerProvider(trace.WithSpanProcessor(clientUnarySR)) clientStreamSR := tracetest.NewSpanRecorder() clientStreamTP := trace.NewTracerProvider(trace.WithSpanProcessor(clientStreamSR)) serverUnarySR := tracetest.NewSpanRecorder() serverUnaryTP := trace.NewTracerProvider(trace.WithSpanProcessor(serverUnarySR)) serverUnaryMetricReader := metric.NewManualReader() serverUnaryMP := metric.NewMeterProvider(metric.WithReader(serverUnaryMetricReader)) serverStreamSR := tracetest.NewSpanRecorder() serverStreamTP := trace.NewTracerProvider(trace.WithSpanProcessor(serverStreamSR)) assert.NoError(t, doCalls( []grpc.DialOption{ grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(clientUnaryTP))), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(clientStreamTP))), }, []grpc.ServerOption{ grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(serverUnaryTP), otelgrpc.WithMeterProvider(serverUnaryMP))), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(serverStreamTP))), }, )) t.Run("UnaryClientSpans", func(t *testing.T) { checkUnaryClientSpans(t, clientUnarySR.Ended()) }) t.Run("StreamClientSpans", func(t *testing.T) { checkStreamClientSpans(t, clientStreamSR.Ended()) }) t.Run("UnaryServerSpans", func(t *testing.T) { checkUnaryServerSpans(t, serverUnarySR.Ended()) checkUnaryServerRecords(t, serverUnaryMetricReader) }) t.Run("StreamServerSpans", func(t *testing.T) { checkStreamServerSpans(t, serverStreamSR.Ended()) }) } func checkUnaryClientSpans(t *testing.T, spans []trace.ReadOnlySpan) { require.Len(t, spans, 2) emptySpan := spans[0] assert.False(t, emptySpan.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/EmptyCall", emptySpan.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, }, emptySpan.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("EmptyCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, emptySpan.Attributes()) largeSpan := spans[1] assert.False(t, largeSpan.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/UnaryCall", largeSpan.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), // largeReqSize from "google.golang.org/grpc/interop" + 12 (overhead). }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), // largeRespSize from "google.golang.org/grpc/interop" + 8 (overhead). }, }, }, largeSpan.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("UnaryCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, largeSpan.Attributes()) } func checkStreamClientSpans(t *testing.T, spans []trace.ReadOnlySpan) { require.Len(t, spans, 3) streamInput := spans[0] assert.False(t, streamInput.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/StreamingInputCall", streamInput.Name()) // sizes from reqSizes in "google.golang.org/grpc/interop". assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, // client does not record an event for the server response. }, streamInput.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("StreamingInputCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, streamInput.Attributes()) streamOutput := spans[1] assert.False(t, streamOutput.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/StreamingOutputCall", streamOutput.Name()) // sizes from respSizes in "google.golang.org/grpc/interop". assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, }, streamOutput.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("StreamingOutputCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, streamOutput.Attributes()) pingPong := spans[2] assert.False(t, pingPong.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/FullDuplexCall", pingPong.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, }, pingPong.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("FullDuplexCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, pingPong.Attributes()) } func checkStreamServerSpans(t *testing.T, spans []trace.ReadOnlySpan) { require.Len(t, spans, 3) streamInput := spans[0] assert.False(t, streamInput.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/StreamingInputCall", streamInput.Name()) // sizes from reqSizes in "google.golang.org/grpc/interop". assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, }, streamInput.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("StreamingInputCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, streamInput.Attributes()) streamOutput := spans[1] assert.False(t, streamOutput.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/StreamingOutputCall", streamOutput.Name()) // sizes from respSizes in "google.golang.org/grpc/interop". assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, }, streamOutput.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("StreamingOutputCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, streamOutput.Attributes()) pingPong := spans[2] assert.False(t, pingPong.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/FullDuplexCall", pingPong.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(2), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(3), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(4), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, }, pingPong.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("FullDuplexCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, pingPong.Attributes()) } func checkUnaryServerSpans(t *testing.T, spans []trace.ReadOnlySpan) { require.Len(t, spans, 2) emptySpan := spans[0] assert.False(t, emptySpan.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/EmptyCall", emptySpan.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), }, }, }, emptySpan.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("EmptyCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, emptySpan.Attributes()) largeSpan := spans[1] assert.False(t, largeSpan.EndTime().IsZero()) assert.Equal(t, "grpc.testing.TestService/UnaryCall", largeSpan.Name()) assertEvents(t, []trace.Event{ { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("RECEIVED"), // largeReqSize from "google.golang.org/grpc/interop" + 12 (overhead). }, }, { Name: "message", Attributes: []attribute.KeyValue{ otelgrpc.RPCMessageIDKey.Int(1), otelgrpc.RPCMessageTypeKey.String("SENT"), // largeRespSize from "google.golang.org/grpc/interop" + 8 (overhead). }, }, }, largeSpan.Events()) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod("UnaryCall"), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, largeSpan.Attributes()) } func assertEvents(t *testing.T, expected, actual []trace.Event) bool { if !assert.Len(t, actual, len(expected)) { return false } var failed bool for i, e := range expected { if !assert.Equal(t, e.Name, actual[i].Name, "names do not match") { failed = true } if !assert.ElementsMatch(t, e.Attributes, actual[i].Attributes, "attributes do not match: %s", e.Name) { failed = true } } return !failed } func checkUnaryServerRecords(t *testing.T, reader metric.Reader) { rm := metricdata.ResourceMetrics{} err := reader.Collect(context.Background(), &rm) assert.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 1) require.IsType(t, rm.ScopeMetrics[0].Metrics[0].Data, metricdata.Histogram[int64]{}) data := rm.ScopeMetrics[0].Metrics[0].Data.(metricdata.Histogram[int64]) for _, dpt := range data.DataPoints { attr := dpt.Attributes.ToSlice() method := getRPCMethod(attr) assert.NotEmpty(t, method) assert.ElementsMatch(t, []attribute.KeyValue{ semconv.RPCMethod(method), semconv.RPCService("grpc.testing.TestService"), otelgrpc.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(codes.OK)), }, attr) } } func getRPCMethod(attrs []attribute.KeyValue) string { for _, kvs := range attrs { if kvs.Key == semconv.RPCMethodKey { return kvs.Value.AsString() } } return "" } interceptor_test.go000066400000000000000000000612271443314701600400040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "errors" "io" "net" "strings" "testing" "time" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/internal" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" "google.golang.org/grpc" grpc_codes "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" ) func getSpanFromRecorder(sr *tracetest.SpanRecorder, name string) (trace.ReadOnlySpan, bool) { for _, s := range sr.Ended() { if s.Name() == name { return s, true } } return nil, false } type mockUICInvoker struct { ctx context.Context } func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error { mcuici.ctx = ctx // if method contains error name, mock error return if strings.Contains(method, "error") { return status.Error(grpc_codes.Internal, "internal error") } return nil } func ctxDialer() func(context.Context, string) (net.Conn, error) { l := bufconn.Listen(0) return func(ctx context.Context, _ string) (net.Conn, error) { return l.DialContext(ctx) } } func TestUnaryClientInterceptor(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) clientConn, err := grpc.DialContext(ctx, "fake:8906", grpc.WithContextDialer(ctxDialer()), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { t.Fatalf("failed to create client connection: %v", err) } defer clientConn.Close() sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) unaryInterceptor := otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tp)) req := &grpc_testing.SimpleRequest{} reply := &grpc_testing.SimpleResponse{} uniInterceptorInvoker := &mockUICInvoker{} checks := []struct { method string name string expectedSpanCode codes.Code expectedAttr []attribute.KeyValue eventsAttr []map[attribute.Key]attribute.Value expectErr bool }{ { method: "/github.com.serviceName/bar", name: "github.com.serviceName/bar", expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, semconv.RPCService("github.com.serviceName"), semconv.RPCMethod("bar"), otelgrpc.GRPCStatusCodeKey.Int64(0), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, }, { method: "/serviceName/bar", name: "serviceName/bar", expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, semconv.RPCService("serviceName"), semconv.RPCMethod("bar"), otelgrpc.GRPCStatusCodeKey.Int64(0), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, }, { method: "serviceName/bar", name: "serviceName/bar", expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, semconv.RPCService("serviceName"), semconv.RPCMethod("bar"), otelgrpc.GRPCStatusCodeKey.Int64(int64(grpc_codes.OK)), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, }, { method: "serviceName/bar_error", name: "serviceName/bar_error", expectedSpanCode: codes.Error, expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, semconv.RPCService("serviceName"), semconv.RPCMethod("bar_error"), otelgrpc.GRPCStatusCodeKey.Int64(int64(grpc_codes.Internal)), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, expectErr: true, }, { method: "invalidName", name: "invalidName", expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(0), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, }, { method: "/github.com.foo.serviceName_123/method", name: "github.com.foo.serviceName_123/method", expectedAttr: []attribute.KeyValue{ semconv.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(0), semconv.RPCService("github.com.foo.serviceName_123"), semconv.RPCMethod("method"), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), }, eventsAttr: []map[attribute.Key]attribute.Value{ { otelgrpc.RPCMessageTypeKey: attribute.StringValue("SENT"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, { otelgrpc.RPCMessageTypeKey: attribute.StringValue("RECEIVED"), otelgrpc.RPCMessageIDKey: attribute.IntValue(1), }, }, }, } for _, check := range checks { err := unaryInterceptor(context.Background(), check.method, req, reply, clientConn, uniInterceptorInvoker.invoker) if check.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) } span, ok := getSpanFromRecorder(sr, check.name) if !assert.True(t, ok, "missing span %q", check.name) { continue } assert.Equal(t, check.expectedSpanCode, span.Status().Code) assert.ElementsMatch(t, check.expectedAttr, span.Attributes()) assert.Equal(t, check.eventsAttr, eventAttrMap(span.Events())) } } func eventAttrMap(events []trace.Event) []map[attribute.Key]attribute.Value { maps := make([]map[attribute.Key]attribute.Value, len(events)) for i, event := range events { maps[i] = make(map[attribute.Key]attribute.Value, len(event.Attributes)) for _, a := range event.Attributes { maps[i][a.Key] = a.Value } } return maps } type mockClientStream struct { Desc *grpc.StreamDesc Ctx context.Context msgs []grpc_testing.SimpleResponse } func (mockClientStream) SendMsg(m interface{}) error { return nil } func (c *mockClientStream) RecvMsg(m interface{}) error { if len(c.msgs) == 0 { return io.EOF } c.msgs = c.msgs[1:] return nil } func (mockClientStream) CloseSend() error { return nil } func (c mockClientStream) Context() context.Context { return c.Ctx } func (mockClientStream) Header() (metadata.MD, error) { return nil, nil } func (mockClientStream) Trailer() metadata.MD { return nil } type clientStreamOpts struct { NumRecvMsgs int DisableServerStreams bool } func newMockClientStream(opts clientStreamOpts) *mockClientStream { var msgs []grpc_testing.SimpleResponse for i := 0; i < opts.NumRecvMsgs; i++ { msgs = append(msgs, grpc_testing.SimpleResponse{}) } return &mockClientStream{msgs: msgs} } func createInterceptedStreamClient(t *testing.T, method string, opts clientStreamOpts) (grpc.ClientStream, *tracetest.SpanRecorder) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) mockStream := newMockClientStream(opts) clientConn, err := grpc.DialContext(ctx, "fake:8906", grpc.WithContextDialer(ctxDialer()), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { t.Fatalf("failed to create client connection: %v", err) } defer clientConn.Close() // tracer sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) streamCI := otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tp)) streamClient, err := streamCI( context.Background(), &grpc.StreamDesc{ServerStreams: !opts.DisableServerStreams}, clientConn, method, func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { mockStream.Desc = desc mockStream.Ctx = ctx return mockStream, nil }, ) require.NoError(t, err, "initialize grpc stream client") return streamClient, sr } func TestStreamClientInterceptorOnBIDIStream(t *testing.T) { defer goleak.VerifyNone(t) method := "/github.com.serviceName/bar" name := "github.com.serviceName/bar" streamClient, sr := createInterceptedStreamClient(t, method, clientStreamOpts{NumRecvMsgs: 10}) _, ok := getSpanFromRecorder(sr, name) require.False(t, ok, "span should not end while stream is open") req := &grpc_testing.SimpleRequest{} reply := &grpc_testing.SimpleResponse{} // send and receive fake data for i := 0; i < 10; i++ { _ = streamClient.SendMsg(req) _ = streamClient.RecvMsg(reply) } // The stream has been exhausted so next read should get a EOF and the stream should be considered closed. err := streamClient.RecvMsg(reply) require.Equal(t, io.EOF, err) // added retry because span end is called in separate go routine var span trace.ReadOnlySpan for retry := 0; retry < 5; retry++ { span, ok = getSpanFromRecorder(sr, name) if ok { break } time.Sleep(time.Second * 1) } require.True(t, ok, "missing span %s", name) expectedAttr := []attribute.KeyValue{ semconv.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(grpc_codes.OK)), semconv.RPCService("github.com.serviceName"), semconv.RPCMethod("bar"), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), } assert.ElementsMatch(t, expectedAttr, span.Attributes()) events := span.Events() require.Len(t, events, 20) for i := 0; i < 20; i += 2 { msgID := i/2 + 1 validate := func(eventName string, attrs []attribute.KeyValue) { for _, kv := range attrs { k, v := kv.Key, kv.Value if k == otelgrpc.RPCMessageTypeKey && v.AsString() != eventName { t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, v.AsString()) } if k == otelgrpc.RPCMessageIDKey && v != attribute.IntValue(msgID) { t.Errorf("invalid id for message event expected %d received %d", msgID, v.AsInt64()) } } } validate("SENT", events[i].Attributes) validate("RECEIVED", events[i+1].Attributes) } // ensure CloseSend can be subsequently called _ = streamClient.CloseSend() } func TestStreamClientInterceptorOnUnidirectionalClientServerStream(t *testing.T) { defer goleak.VerifyNone(t) method := "/github.com.serviceName/bar" name := "github.com.serviceName/bar" opts := clientStreamOpts{NumRecvMsgs: 1, DisableServerStreams: true} streamClient, sr := createInterceptedStreamClient(t, method, opts) _, ok := getSpanFromRecorder(sr, name) require.False(t, ok, "span should not end while stream is open") req := &grpc_testing.SimpleRequest{} reply := &grpc_testing.SimpleResponse{} // send fake data for i := 0; i < 10; i++ { _ = streamClient.SendMsg(req) } // A real user would call CloseAndRecv() on the generated client which would generate a sequence of CloseSend() // and RecvMsg() calls. _ = streamClient.CloseSend() err := streamClient.RecvMsg(reply) require.Nil(t, err) // added retry because span end is called in separate go routine var span trace.ReadOnlySpan for retry := 0; retry < 5; retry++ { span, ok = getSpanFromRecorder(sr, name) if ok { break } time.Sleep(time.Second * 1) } require.True(t, ok, "missing span %s", name) expectedAttr := []attribute.KeyValue{ semconv.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(grpc_codes.OK)), semconv.RPCService("github.com.serviceName"), semconv.RPCMethod("bar"), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), } assert.ElementsMatch(t, expectedAttr, span.Attributes()) // Note that there's no "RECEIVED" event generated for the server response. This is a bug. events := span.Events() require.Len(t, events, 10) for i := 0; i < 10; i++ { msgID := i + 1 validate := func(eventName string, attrs []attribute.KeyValue) { for _, kv := range attrs { k, v := kv.Key, kv.Value if k == otelgrpc.RPCMessageTypeKey && v.AsString() != eventName { t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, v.AsString()) } if k == otelgrpc.RPCMessageIDKey && v != attribute.IntValue(msgID) { t.Errorf("invalid id for message event expected %d received %d", msgID, v.AsInt64()) } } } validate("SENT", events[i].Attributes) } } // TestStreamClientInterceptorCancelContext tests a cancel context situation. // There should be no goleaks. func TestStreamClientInterceptorCancelContext(t *testing.T) { defer goleak.VerifyNone(t) ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) clientConn, err := grpc.DialContext(ctx, "fake:8906", grpc.WithContextDialer(ctxDialer()), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { t.Fatalf("failed to create client connection: %v", err) } defer clientConn.Close() // tracer sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) streamCI := otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tp)) var mockClStr *mockClientStream method := "/github.com.serviceName/bar" name := "github.com.serviceName/bar" // create a context with cancel cancelCtx, cancel := context.WithCancel(context.Background()) defer cancel() streamClient, err := streamCI( cancelCtx, &grpc.StreamDesc{ServerStreams: true}, clientConn, method, func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { mockClStr = &mockClientStream{Desc: desc, Ctx: ctx} return mockClStr, nil }, ) require.NoError(t, err, "initialize grpc stream client") _, ok := getSpanFromRecorder(sr, name) require.False(t, ok, "span should not ended while stream is open") req := &grpc_testing.SimpleRequest{} reply := &grpc_testing.SimpleResponse{} // send and receive fake data for i := 0; i < 10; i++ { _ = streamClient.SendMsg(req) _ = streamClient.RecvMsg(reply) } // close client stream _ = streamClient.CloseSend() } // TestStreamClientInterceptorWithError tests a situation that streamer returns an error. func TestStreamClientInterceptorWithError(t *testing.T) { defer goleak.VerifyNone(t) ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) clientConn, err := grpc.DialContext(ctx, "fake:8906", grpc.WithContextDialer(ctxDialer()), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { t.Fatalf("failed to create client connection: %v", err) } defer clientConn.Close() // tracer sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) streamCI := otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tp)) var mockClStr *mockClientStream method := "/github.com.serviceName/bar" name := "github.com.serviceName/bar" streamClient, err := streamCI( context.Background(), &grpc.StreamDesc{ServerStreams: true}, clientConn, method, func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { mockClStr = &mockClientStream{Desc: desc, Ctx: ctx} return mockClStr, errors.New("test") }, ) require.Error(t, err, "initialize grpc stream client") assert.IsType(t, &mockClientStream{}, streamClient) span, ok := getSpanFromRecorder(sr, name) require.True(t, ok, "missing span %s", name) expectedAttr := []attribute.KeyValue{ semconv.RPCSystemGRPC, otelgrpc.GRPCStatusCodeKey.Int64(int64(grpc_codes.Unknown)), semconv.RPCService("github.com.serviceName"), semconv.RPCMethod("bar"), semconv.NetPeerName("fake"), semconv.NetPeerPort(8906), } assert.ElementsMatch(t, expectedAttr, span.Attributes()) assert.Equal(t, codes.Error, span.Status().Code) } var serverChecks = []struct { grpcCode grpc_codes.Code wantSpanCode codes.Code wantSpanStatusDescription string }{ { grpcCode: grpc_codes.OK, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.Canceled, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.Unknown, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.Unknown.String(), }, { grpcCode: grpc_codes.InvalidArgument, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.DeadlineExceeded, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.DeadlineExceeded.String(), }, { grpcCode: grpc_codes.NotFound, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.AlreadyExists, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.PermissionDenied, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.ResourceExhausted, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.FailedPrecondition, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.Aborted, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.OutOfRange, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, { grpcCode: grpc_codes.Unimplemented, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.Unimplemented.String(), }, { grpcCode: grpc_codes.Internal, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.Internal.String(), }, { grpcCode: grpc_codes.Unavailable, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.Unavailable.String(), }, { grpcCode: grpc_codes.DataLoss, wantSpanCode: codes.Error, wantSpanStatusDescription: grpc_codes.DataLoss.String(), }, { grpcCode: grpc_codes.Unauthenticated, wantSpanCode: codes.Unset, wantSpanStatusDescription: "", }, } func assertServerSpan(t *testing.T, wantSpanCode codes.Code, wantSpanStatusDescription string, wantGrpcCode grpc_codes.Code, span trace.ReadOnlySpan) { // validate span status assert.Equal(t, wantSpanCode, span.Status().Code) assert.Equal(t, wantSpanStatusDescription, span.Status().Description) // validate grpc code span attribute var codeAttr attribute.KeyValue for _, a := range span.Attributes() { if a.Key == otelgrpc.GRPCStatusCodeKey { codeAttr = a break } } require.True(t, codeAttr.Valid(), "attributes contain gRPC status code") assert.Equal(t, attribute.Int64Value(int64(wantGrpcCode)), codeAttr.Value) } // TestUnaryServerInterceptor tests the server interceptor for unary RPCs. func TestUnaryServerInterceptor(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) usi := otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(tp)) for _, check := range serverChecks { name := check.grpcCode.String() t.Run(name, func(t *testing.T) { // call the unary interceptor grpcErr := status.Error(check.grpcCode, check.grpcCode.String()) handler := func(_ context.Context, _ interface{}) (interface{}, error) { return nil, grpcErr } _, err := usi(context.Background(), &grpc_testing.SimpleRequest{}, &grpc.UnaryServerInfo{FullMethod: name}, handler) assert.Equal(t, grpcErr, err) // validate span span, ok := getSpanFromRecorder(sr, name) require.True(t, ok, "missing span %s", name) assertServerSpan(t, check.wantSpanCode, check.wantSpanStatusDescription, check.grpcCode, span) // validate events and their attributes assert.Len(t, span.Events(), 2) assert.ElementsMatch(t, []attribute.KeyValue{ attribute.Key("message.type").String("SENT"), attribute.Key("message.id").Int(1), }, span.Events()[1].Attributes) }) } } type mockServerStream struct { grpc.ServerStream } func (m *mockServerStream) Context() context.Context { return context.Background() } // TestStreamServerInterceptor tests the server interceptor for streaming RPCs. func TestStreamServerInterceptor(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) usi := otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(tp)) for _, check := range serverChecks { name := check.grpcCode.String() t.Run(name, func(t *testing.T) { // call the stream interceptor grpcErr := status.Error(check.grpcCode, check.grpcCode.String()) handler := func(_ interface{}, _ grpc.ServerStream) error { return grpcErr } err := usi(&grpc_testing.SimpleRequest{}, &mockServerStream{}, &grpc.StreamServerInfo{FullMethod: name}, handler) assert.Equal(t, grpcErr, err) // validate span span, ok := getSpanFromRecorder(sr, name) require.True(t, ok, "missing span %s", name) assertServerSpan(t, check.wantSpanCode, check.wantSpanStatusDescription, check.grpcCode, span) }) } } func TestParseFullMethod(t *testing.T) { tests := []struct { fullMethod string name string attr []attribute.KeyValue }{ { fullMethod: "/grpc.test.EchoService/Echo", name: "grpc.test.EchoService/Echo", attr: []attribute.KeyValue{ semconv.RPCService("grpc.test.EchoService"), semconv.RPCMethod("Echo"), }, }, { fullMethod: "/com.example.ExampleRmiService/exampleMethod", name: "com.example.ExampleRmiService/exampleMethod", attr: []attribute.KeyValue{ semconv.RPCService("com.example.ExampleRmiService"), semconv.RPCMethod("exampleMethod"), }, }, { fullMethod: "/MyCalcService.Calculator/Add", name: "MyCalcService.Calculator/Add", attr: []attribute.KeyValue{ semconv.RPCService("MyCalcService.Calculator"), semconv.RPCMethod("Add"), }, }, { fullMethod: "/MyServiceReference.ICalculator/Add", name: "MyServiceReference.ICalculator/Add", attr: []attribute.KeyValue{ semconv.RPCService("MyServiceReference.ICalculator"), semconv.RPCMethod("Add"), }, }, { fullMethod: "/MyServiceWithNoPackage/theMethod", name: "MyServiceWithNoPackage/theMethod", attr: []attribute.KeyValue{ semconv.RPCService("MyServiceWithNoPackage"), semconv.RPCMethod("theMethod"), }, }, { fullMethod: "/pkg.srv", name: "pkg.srv", attr: []attribute.KeyValue(nil), }, { fullMethod: "/pkg.srv/", name: "pkg.srv/", attr: []attribute.KeyValue{ semconv.RPCService("pkg.srv"), }, }, } for _, test := range tests { n, a := internal.ParseFullMethod(test.fullMethod) assert.Equal(t, test.name, n) assert.Equal(t, test.attr, a) } } version.go000066400000000000000000000020561443314701600360670ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/test" // Version is the current release version of the gRPC instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020411443314701600351020ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/google.golang.org/grpc/otelgrpc// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" // Version is the current release version of the gRPC instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/000077500000000000000000000000001443314701600266025ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/000077500000000000000000000000001443314701600305475ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/000077500000000000000000000000001443314701600330535ustar00rootroot00000000000000config.go000066400000000000000000000040431443314701600345710ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmacaron // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) // config is a group of options for this instrumentation. type config struct { TracerProvider trace.TracerProvider Propagators propagation.TextMapPropagator } // Option applies an option value for a config. type Option interface { apply(*config) } // newConfig returns a config configured with all the passed Options. func newConfig(opts []Option) *config { c := &config{ Propagators: otel.GetTextMapPropagator(), TracerProvider: otel.GetTracerProvider(), } for _, o := range opts { o.apply(c) } return c } type propagatorsOption struct{ p propagation.TextMapPropagator } func (o propagatorsOption) apply(c *config) { if o.p != nil { c.Propagators = o.p } } // WithPropagators returns an Option to use the Propagators when extracting // and injecting trace context from HTTP requests. func WithPropagators(p propagation.TextMapPropagator) Option { return propagatorsOption{p: p} } type tracerProviderOption struct{ tp trace.TracerProvider } func (o tracerProviderOption) apply(c *config) { if o.tp != nil { c.TracerProvider = o.tp } } // WithTracerProvider returns an Option to use the TracerProvider when // creating a Tracer. func WithTracerProvider(tp trace.TracerProvider) Option { return tracerProviderOption{tp: tp} } doc.go000066400000000000000000000015601443314701600340720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelmacaron instruments gopkg.in/macaron.v1. // // Currently only the routing of a received message can be instrumented. To do // it, use the Middleware function. package otelmacaron // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" example/000077500000000000000000000000001443314701600344275ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaronDockerfile000066400000000000000000000014041443314701600364200ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:alpine AS base COPY . /src/ WORKDIR /src/instrumentation/gopkg.in/macaron.v1/otelmacaron/example FROM base AS macaron-server RUN go install ./server.go CMD ["/go/bin/server"] README.md000066400000000000000000000000001443314701600356740ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/exampledocker-compose.yml000066400000000000000000000021171443314701600400650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: macaron-client: image: golang:alpine networks: - example command: - "/bin/sh" - "-c" - "wget http://macaron-server:8080/users/123 && cat 123" depends_on: - macaron-server macaron-server: build: dockerfile: $PWD/Dockerfile context: ../../../../.. ports: - "8080:80" command: - "/bin/sh" - "-c" - "/go/bin/server" networks: - example environment: - PORT=80 networks: example: go.mod000066400000000000000000000017371443314701600355450ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/examplemodule go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../propagators/b3 ) require ( go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 gopkg.in/macaron.v1 v1.5.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect ) go.sum000066400000000000000000000071621443314701600355700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/examplegithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/macaron.v1 v1.5.0 h1:/dXJaeQagWLjVjCrKH8dgSSU7yG4qTv6rBKpqhYaCyc= gopkg.in/macaron.v1 v1.5.0/go.mod h1:sAYUd2r8Q+jLnCN4/ZmdAYHzQn67agV5sAqKFQgrRrw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server.go000066400000000000000000000041721443314701600362700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/example// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "gopkg.in/macaron.v1" "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) var tracer = otel.Tracer("macaron-server") func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() m := macaron.Classic() m.Use(otelmacaron.Middleware("my-server")) m.Get("/users/:id", func(ctx *macaron.Context) string { id := ctx.Params("id") name := getUser(ctx.Req.Context(), id) return name }) m.Run() } func initTracer() (*sdktrace.TracerProvider, error) { exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func getUser(ctx context.Context, id string) string { _, span := tracer.Start(ctx, "getUser", oteltrace.WithAttributes(attribute.String("id", id))) defer span.End() if id == "123" { return "otelmacaron tester" } return "unknown" } go.mod000066400000000000000000000015721443314701600341070ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaronmodule go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron go 1.19 replace go.opentelemetry.io/contrib/propagators/b3 => ../../../../propagators/b3 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 gopkg.in/macaron.v1 v1.5.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) go.sum000066400000000000000000000071661443314701600341410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacarongithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/macaron.v1 v1.5.0 h1:/dXJaeQagWLjVjCrKH8dgSSU7yG4qTv6rBKpqhYaCyc= gopkg.in/macaron.v1 v1.5.0/go.mod h1:sAYUd2r8Q+jLnCN4/ZmdAYHzQn67agV5sAqKFQgrRrw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= macaron.go000066400000000000000000000046471443314701600347560ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmacaron // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" import ( "fmt" "net/http" "gopkg.in/macaron.v1" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" oteltrace "go.opentelemetry.io/otel/trace" ) // instrumentationName is the name of this instrumentation package. const instrumentationName = "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" // Middleware returns a macaron Handler to trace requests to the server. func Middleware(service string, opts ...Option) macaron.Handler { cfg := newConfig(opts) tracer := cfg.TracerProvider.Tracer( instrumentationName, oteltrace.WithInstrumentationVersion(Version()), ) return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { savedCtx := c.Req.Request.Context() defer func() { c.Req.Request = c.Req.Request.WithContext(savedCtx) }() ctx := cfg.Propagators.Extract(savedCtx, propagation.HeaderCarrier(c.Req.Header)) opts := []oteltrace.SpanStartOption{ oteltrace.WithAttributes(httpconv.ServerRequest(service, c.Req.Request)...), oteltrace.WithSpanKind(oteltrace.SpanKindServer), } // TODO: span name should be router template not the actual request path, eg /user/:id vs /user/123 spanName := c.Req.RequestURI if spanName == "" { spanName = fmt.Sprintf("HTTP %s route not found", c.Req.Method) } ctx, span := tracer.Start(ctx, spanName, opts...) defer span.End() // pass the span through the request context c.Req.Request = c.Req.Request.WithContext(ctx) // serve the request to the next middleware c.Next() status := c.Resp.Status() span.SetStatus(httpconv.ServerStatus(status)) if status > 0 { span.SetAttributes(semconv.HTTPStatusCode(status)) } } } macaron_test.go000066400000000000000000000063221443314701600360050ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmacaron import ( "context" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "gopkg.in/macaron.v1" b3prop "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" oteltrace "go.opentelemetry.io/otel/trace" ) func TestGetSpanNotInstrumented(t *testing.T) { m := macaron.Classic() m.Get("/user/:id", func(ctx *macaron.Context) { span := oteltrace.SpanFromContext(ctx.Req.Request.Context()) ok := !span.SpanContext().IsValid() assert.True(t, ok) ctx.Resp.WriteHeader(http.StatusOK) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() m.ServeHTTP(w, r) } func TestPropagationWithGlobalPropagators(t *testing.T) { tracer := oteltrace.NewNoopTracerProvider().Tracer("test-tracer") otel.SetTextMapPropagator(propagation.TraceContext{}) otel.SetTracerProvider(oteltrace.NewNoopTracerProvider()) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, }) ctx = oteltrace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = tracer.Start(ctx, "test") otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) m := macaron.Classic() m.Use(Middleware("foobar")) m.Get("/user/:id", func(ctx *macaron.Context) { span := oteltrace.SpanFromContext(ctx.Req.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) ctx.Resp.WriteHeader(http.StatusOK) }) m.ServeHTTP(w, r) } func TestPropagationWithCustomPropagators(t *testing.T) { tp := oteltrace.NewNoopTracerProvider() otel.SetTracerProvider(tp) tracer := tp.Tracer("test-tracer") b3 := b3prop.New() r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() ctx := context.Background() sc := oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ TraceID: oteltrace.TraceID{0x01}, SpanID: oteltrace.SpanID{0x01}, }) ctx = oteltrace.ContextWithRemoteSpanContext(ctx, sc) ctx, _ = tracer.Start(ctx, "test") b3.Inject(ctx, propagation.HeaderCarrier(r.Header)) m := macaron.Classic() m.Use(Middleware("foobar", WithTracerProvider(tp), WithPropagators(b3))) m.Get("/user/:id", func(ctx *macaron.Context) { span := oteltrace.SpanFromContext(ctx.Req.Request.Context()) assert.Equal(t, sc.TraceID(), span.SpanContext().TraceID()) assert.Equal(t, sc.SpanID(), span.SpanContext().SpanID()) ctx.Resp.WriteHeader(http.StatusOK) }) m.ServeHTTP(w, r) } test/000077500000000000000000000000001443314701600337535ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacarondoc.go000066400000000000000000000017021443314701600350470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelmacaron instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/test" go.mod000066400000000000000000000021071443314701600350610ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/testmodule go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/test go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 gopkg.in/macaron.v1 v1.5.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace ( go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron => ../ go.opentelemetry.io/contrib/propagators/b3 => ../../../../../propagators/b3 ) go.sum000066400000000000000000000076761443314701600351260ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/testgithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/macaron.v1 v1.5.0 h1:/dXJaeQagWLjVjCrKH8dgSSU7yG4qTv6rBKpqhYaCyc= gopkg.in/macaron.v1 v1.5.0/go.mod h1:sAYUd2r8Q+jLnCN4/ZmdAYHzQn67agV5sAqKFQgrRrw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= macaron_test.go000066400000000000000000000077141443314701600367720ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "net/http" "net/http/httptest" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/macaron.v1" "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" oteltrace "go.opentelemetry.io/otel/trace" ) func TestChildSpanFromGlobalTracer(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) otel.SetTracerProvider(tp) m := macaron.Classic() m.Use(otelmacaron.Middleware("foobar")) m.Get("/user/:id", func(ctx *macaron.Context) { ctx.Resp.WriteHeader(http.StatusOK) }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() m.ServeHTTP(w, r) assert.Len(t, sr.Ended(), 1) } func TestChildSpanNames(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) m := macaron.Classic() m.Use(otelmacaron.Middleware("foobar", otelmacaron.WithTracerProvider(tp))) m.Get("/user/:id", func(ctx *macaron.Context) { ctx.Resp.WriteHeader(http.StatusOK) }) m.Get("/book/:title", func(ctx *macaron.Context) { _, err := ctx.Resp.Write(([]byte)("ok")) if err != nil { t.Error(err) } }) r := httptest.NewRequest("GET", "/user/123", nil) w := httptest.NewRecorder() m.ServeHTTP(w, r) r = httptest.NewRequest("GET", "/book/foo", nil) w = httptest.NewRecorder() m.ServeHTTP(w, r) spans := sr.Ended() require.Len(t, spans, 2) span := spans[0] assert.Equal(t, "/user/123", span.Name()) // TODO: span name should show router template, eg /user/:id assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) attrs := span.Attributes() assert.Contains(t, attrs, attribute.String("net.host.name", "foobar")) assert.Contains(t, attrs, attribute.Int("http.status_code", http.StatusOK)) assert.Contains(t, attrs, attribute.String("http.method", "GET")) span = spans[1] assert.Equal(t, "/book/foo", span.Name()) // TODO: span name should show router template, eg /book/:title assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) attrs = span.Attributes() assert.Contains(t, attrs, attribute.String("net.host.name", "foobar")) assert.Contains(t, attrs, attribute.Int("http.status_code", http.StatusOK)) assert.Contains(t, attrs, attribute.String("http.method", "GET")) } func TestSpanStatus(t *testing.T) { testCases := []struct { httpStatusCode int wantSpanStatus codes.Code }{ {http.StatusOK, codes.Unset}, {http.StatusBadRequest, codes.Unset}, {http.StatusInternalServerError, codes.Error}, } for _, tc := range testCases { t.Run(strconv.Itoa(tc.httpStatusCode), func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider() provider.RegisterSpanProcessor(sr) m := macaron.Classic() m.Use(otelmacaron.Middleware("foobar", otelmacaron.WithTracerProvider(provider))) m.Get("/", func(ctx *macaron.Context) { ctx.Resp.WriteHeader(tc.httpStatusCode) }) m.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) require.Len(t, sr.Ended(), 1, "should emit a span") assert.Equal(t, sr.Ended()[0].Status().Code, tc.wantSpanStatus, "should only set Error status for HTTP statuses >= 500") }) } } version.go000066400000000000000000000020601443314701600357650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/test" // Version is the current release version of the macron instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020461443314701600350120ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/gopkg.in/macaron.v1/otelmacaron// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelmacaron // import "go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron" // Version is the current release version of the macron instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/000077500000000000000000000000001443314701600260435ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/doc.go000066400000000000000000000031121443314701600271340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package host provides the conventional host metric instruments // specified by OpenTelemetry. Host metric events are sometimes // collected through the OpenTelemetry Collector "hostmetrics" // receiver running as an agent; this instrumentation is an // alternative for processes that want to record the same information // without an agent. // // The metric events produced are listed here with attribute dimensions. // // Name Attribute // // ---------------------------------------------------------------------- // // process.cpu.time state=user|system // system.cpu.time state=user|system|other|idle // system.memory.usage state=used|available // system.memory.utilization state=used|available // system.network.io direction=transmit|receive // // See https://github.com/open-telemetry/oteps/blob/main/text/0119-standard-system-metrics.md // for the definition of these metric instruments. package host // import "go.opentelemetry.io/contrib/instrumentation/host" open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/example/000077500000000000000000000000001443314701600274765ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/example/doc.go000066400000000000000000000012511443314701600305710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package main provides and example use of the host instrumentation. package main open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/example/go.mod000066400000000000000000000020721443314701600306050ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/host/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/host => ../ require ( go.opentelemetry.io/contrib/instrumentation/host v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil/v3 v3.23.4 // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/example/go.sum000066400000000000000000000126321443314701600306350ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 h1:fl2WmyenEf6LYYlfHAtCUEDyGcpwJNqD4dHGO7PVm4w= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0/go.mod h1:csyQxQ0UHHKVA8KApS7eUO/klMO5sd/av5CNZNU4O6w= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/example/main.go000066400000000000000000000032731443314701600307560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build go1.18 // +build go1.18 package main import ( "context" "log" "os" "os/signal" "time" "go.opentelemetry.io/contrib/instrumentation/host" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) var res = resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName("host-instrumentation-example"), ) func main() { exp, err := stdoutmetric.New() if err != nil { log.Fatal(err) } // Register the exporter with an SDK via a periodic reader. read := metric.NewPeriodicReader(exp, metric.WithInterval(1*time.Second)) provider := metric.NewMeterProvider(metric.WithResource(res), metric.WithReader(read)) defer func() { err := provider.Shutdown(context.Background()) if err != nil { log.Fatal(err) } }() ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() log.Print("Starting host instrumentation:") err = host.Start(host.WithMeterProvider(provider)) if err != nil { log.Fatal(err) } <-ctx.Done() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/go.mod000066400000000000000000000014141443314701600271510ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/host go 1.19 require ( github.com/shirou/gopsutil/v3 v3.23.4 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.7.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/go.sum000066400000000000000000000113661443314701600272050ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/host.go000066400000000000000000000210441443314701600273500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package host // import "go.opentelemetry.io/contrib/instrumentation/host" import ( "context" "fmt" "os" "sync" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/net" "github.com/shirou/gopsutil/v3/process" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) // Host reports the work-in-progress conventional host metrics specified by OpenTelemetry. type host struct { config config meter metric.Meter } // config contains optional settings for reporting host metrics. type config struct { // MeterProvider sets the metric.MeterProvider. If nil, the global // Provider will be used. MeterProvider metric.MeterProvider } // Option supports configuring optional settings for host metrics. type Option interface { apply(*config) } // WithMeterProvider sets the Metric implementation to use for // reporting. If this option is not used, the global metric.MeterProvider // will be used. `provider` must be non-nil. func WithMeterProvider(provider metric.MeterProvider) Option { return metricProviderOption{provider} } type metricProviderOption struct{ metric.MeterProvider } func (o metricProviderOption) apply(c *config) { if o.MeterProvider != nil { c.MeterProvider = o.MeterProvider } } // Attribute sets. var ( // Attribute sets for CPU time measurements. AttributeCPUTimeUser = attribute.NewSet(attribute.String("state", "user")) AttributeCPUTimeSystem = attribute.NewSet(attribute.String("state", "system")) AttributeCPUTimeOther = attribute.NewSet(attribute.String("state", "other")) AttributeCPUTimeIdle = attribute.NewSet(attribute.String("state", "idle")) // Attribute sets used for Memory measurements. AttributeMemoryAvailable = attribute.NewSet(attribute.String("state", "available")) AttributeMemoryUsed = attribute.NewSet(attribute.String("state", "used")) // Attribute sets used for Network measurements. AttributeNetworkTransmit = attribute.NewSet(attribute.String("direction", "transmit")) AttributeNetworkReceive = attribute.NewSet(attribute.String("direction", "receive")) ) // newConfig computes a config from a list of Options. func newConfig(opts ...Option) config { c := config{ MeterProvider: otel.GetMeterProvider(), } for _, opt := range opts { opt.apply(&c) } return c } // Start initializes reporting of host metrics using the supplied config. func Start(opts ...Option) error { c := newConfig(opts...) if c.MeterProvider == nil { c.MeterProvider = otel.GetMeterProvider() } h := &host{ meter: c.MeterProvider.Meter( "go.opentelemetry.io/contrib/instrumentation/host", metric.WithInstrumentationVersion(Version()), ), config: c, } return h.register() } func (h *host) register() error { var ( err error processCPUTime metric.Float64ObservableCounter hostCPUTime metric.Float64ObservableCounter hostMemoryUsage metric.Int64ObservableGauge hostMemoryUtilization metric.Float64ObservableGauge networkIOUsage metric.Int64ObservableCounter // lock prevents a race between batch observer and instrument registration. lock sync.Mutex ) proc, err := process.NewProcess(int32(os.Getpid())) if err != nil { return fmt.Errorf("could not find this process: %w", err) } lock.Lock() defer lock.Unlock() // TODO: .time units are in seconds, but "unit" package does // not include this string. // https://github.com/open-telemetry/opentelemetry-specification/issues/705 if processCPUTime, err = h.meter.Float64ObservableCounter( "process.cpu.time", metric.WithUnit("s"), metric.WithDescription( "Accumulated CPU time spent by this process attributeed by state (User, System, ...)", ), ); err != nil { return err } if hostCPUTime, err = h.meter.Float64ObservableCounter( "system.cpu.time", metric.WithUnit("s"), metric.WithDescription( "Accumulated CPU time spent by this host attributeed by state (User, System, Other, Idle)", ), ); err != nil { return err } if hostMemoryUsage, err = h.meter.Int64ObservableGauge( "system.memory.usage", metric.WithUnit("By"), metric.WithDescription( "Memory usage of this process attributed by memory state (Used, Available)", ), ); err != nil { return err } if hostMemoryUtilization, err = h.meter.Float64ObservableGauge( "system.memory.utilization", metric.WithUnit("1"), metric.WithDescription( "Memory utilization of this process attributeed by memory state (Used, Available)", ), ); err != nil { return err } if networkIOUsage, err = h.meter.Int64ObservableCounter( "system.network.io", metric.WithUnit("By"), metric.WithDescription( "Bytes transferred attributeed by direction (Transmit, Receive)", ), ); err != nil { return err } _, err = h.meter.RegisterCallback( func(ctx context.Context, o metric.Observer) error { lock.Lock() defer lock.Unlock() // This follows the OpenTelemetry Collector's "hostmetrics" // receiver/hostmetricsreceiver/internal/scraper/processscraper // measures User and System IOwait time. // TODO: the Collector has per-OS compilation modules to support // specific metrics that are not universal. processTimes, err := proc.TimesWithContext(ctx) if err != nil { return err } hostTimeSlice, err := cpu.TimesWithContext(ctx, false) if err != nil { return err } if len(hostTimeSlice) != 1 { return fmt.Errorf("host CPU usage: incorrect summary count") } vmStats, err := mem.VirtualMemoryWithContext(ctx) if err != nil { return err } ioStats, err := net.IOCountersWithContext(ctx, false) if err != nil { return err } if len(ioStats) != 1 { return fmt.Errorf("host network usage: incorrect summary count") } hostTime := hostTimeSlice[0] opt := metric.WithAttributeSet(AttributeCPUTimeUser) o.ObserveFloat64(processCPUTime, processTimes.User, opt) o.ObserveFloat64(hostCPUTime, hostTime.User, opt) opt = metric.WithAttributeSet(AttributeCPUTimeSystem) o.ObserveFloat64(processCPUTime, processTimes.System, opt) o.ObserveFloat64(hostCPUTime, hostTime.System, opt) // TODO(#244): "other" is a placeholder for actually dealing // with these states. Do users actually want this // (unconditionally)? How should we handle "iowait" // if not all systems expose it? Should we break // these down by CPU? If so, are users going to want // to aggregate in-process? See: // https://github.com/open-telemetry/opentelemetry-go-contrib/issues/244 other := hostTime.Nice + hostTime.Iowait + hostTime.Irq + hostTime.Softirq + hostTime.Steal + hostTime.Guest + hostTime.GuestNice opt = metric.WithAttributeSet(AttributeCPUTimeOther) o.ObserveFloat64(hostCPUTime, other, opt) opt = metric.WithAttributeSet(AttributeCPUTimeIdle) o.ObserveFloat64(hostCPUTime, hostTime.Idle, opt) // Host memory usage opt = metric.WithAttributeSet(AttributeMemoryUsed) o.ObserveInt64(hostMemoryUsage, int64(vmStats.Used), opt) opt = metric.WithAttributeSet(AttributeMemoryAvailable) o.ObserveInt64(hostMemoryUsage, int64(vmStats.Available), opt) // Host memory utilization opt = metric.WithAttributeSet(AttributeMemoryUsed) o.ObserveFloat64(hostMemoryUtilization, float64(vmStats.Used)/float64(vmStats.Total), opt) opt = metric.WithAttributeSet(AttributeMemoryAvailable) o.ObserveFloat64(hostMemoryUtilization, float64(vmStats.Available)/float64(vmStats.Total), opt) // Host network usage // // TODO: These can be broken down by network // interface, with similar questions to those posed // about per-CPU measurements above. opt = metric.WithAttributeSet(AttributeNetworkTransmit) o.ObserveInt64(networkIOUsage, int64(ioStats[0].BytesSent), opt) opt = metric.WithAttributeSet(AttributeNetworkReceive) o.ObserveInt64(networkIOUsage, int64(ioStats[0].BytesRecv), opt) return nil }, processCPUTime, hostCPUTime, hostMemoryUsage, hostMemoryUtilization, networkIOUsage, ) if err != nil { return err } return nil } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/host_test.go000066400000000000000000000016471443314701600304160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package host_test // TODO(#2755): Add integration tests for the host instrumentation. These tests // depend on https://github.com/open-telemetry/opentelemetry-go/issues/3031 // being resolved. // // The added tests will depend on the metric SDK. Therefore, they should be // added to a sub-directory called "test" instead of this file. open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/host/version.go000066400000000000000000000020021443314701600300510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package host // import "go.opentelemetry.io/contrib/instrumentation/host" // Version is the current release version of the host instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/000077500000000000000000000000001443314701600256545ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/000077500000000000000000000000001443314701600266335ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/000077500000000000000000000000001443314701600306315ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/000077500000000000000000000000001443314701600335135ustar00rootroot00000000000000api.go000066400000000000000000000017141443314701600345370ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttptrace // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" import ( "context" "net/http" "net/http/httptrace" ) // W3C client. func W3C(ctx context.Context, req *http.Request) (context.Context, *http.Request) { ctx = httptrace.WithClientTrace(ctx, NewClientTrace(ctx)) req = req.WithContext(ctx) return ctx, req } clienttrace.go000066400000000000000000000272121443314701600362640ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttptrace // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" import ( "context" "crypto/tls" "net/http/httptrace" "net/textproto" "strings" "sync" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) // HTTP attributes. var ( HTTPStatus = attribute.Key("http.status") HTTPHeaderMIME = attribute.Key("http.mime") HTTPRemoteAddr = attribute.Key("http.remote") HTTPLocalAddr = attribute.Key("http.local") HTTPConnectionReused = attribute.Key("http.conn.reused") HTTPConnectionWasIdle = attribute.Key("http.conn.wasidle") HTTPConnectionIdleTime = attribute.Key("http.conn.idletime") HTTPConnectionStartNetwork = attribute.Key("http.conn.start.network") HTTPConnectionDoneNetwork = attribute.Key("http.conn.done.network") HTTPConnectionDoneAddr = attribute.Key("http.conn.done.addr") HTTPDNSAddrs = attribute.Key("http.dns.addrs") ) var ( hookMap = map[string]string{ "http.dns": "http.getconn", "http.connect": "http.getconn", "http.tls": "http.getconn", } ) func parentHook(hook string) string { if strings.HasPrefix(hook, "http.connect") { return hookMap["http.connect"] } return hookMap[hook] } // ClientTraceOption allows customizations to how the httptrace.Client // collects information. type ClientTraceOption interface { apply(*clientTracer) } type clientTraceOptionFunc func(*clientTracer) func (fn clientTraceOptionFunc) apply(c *clientTracer) { fn(c) } // WithoutSubSpans will modify the httptrace.ClientTrace to only collect data // as Events and Attributes on a span found in the context. By default // sub-spans will be generated. func WithoutSubSpans() ClientTraceOption { return clientTraceOptionFunc(func(ct *clientTracer) { ct.useSpans = false }) } // WithRedactedHeaders will be replaced by fixed '****' values for the header // names provided. These are in addition to the sensitive headers already // redacted by default: Authorization, WWW-Authenticate, Proxy-Authenticate // Proxy-Authorization, Cookie, Set-Cookie. func WithRedactedHeaders(headers ...string) ClientTraceOption { return clientTraceOptionFunc(func(ct *clientTracer) { for _, header := range headers { ct.redactedHeaders[strings.ToLower(header)] = struct{}{} } }) } // WithoutHeaders will disable adding span attributes for the http headers // and values. func WithoutHeaders() ClientTraceOption { return clientTraceOptionFunc(func(ct *clientTracer) { ct.addHeaders = false }) } // WithInsecureHeaders will add span attributes for all http headers *INCLUDING* // the sensitive headers that are redacted by default. The attribute values // will include the raw un-redacted text. This might be useful for // debugging authentication related issues, but should not be used for // production deployments. func WithInsecureHeaders() ClientTraceOption { return clientTraceOptionFunc(func(ct *clientTracer) { ct.addHeaders = true ct.redactedHeaders = nil }) } // WithTracerProvider specifies a tracer provider for creating a tracer. // The global provider is used if none is specified. func WithTracerProvider(provider trace.TracerProvider) ClientTraceOption { return clientTraceOptionFunc(func(ct *clientTracer) { if provider != nil { ct.tracerProvider = provider } }) } type clientTracer struct { context.Context tracerProvider trace.TracerProvider tr trace.Tracer activeHooks map[string]context.Context root trace.Span mtx sync.Mutex redactedHeaders map[string]struct{} addHeaders bool useSpans bool } // NewClientTrace returns an httptrace.ClientTrace implementation that will // record OpenTelemetry spans for requests made by an http.Client. By default // several spans will be added to the trace for various stages of a request // (dns, connection, tls, etc). Also by default, all HTTP headers will be // added as attributes to spans, although several headers will be automatically // redacted: Authorization, WWW-Authenticate, Proxy-Authenticate, // Proxy-Authorization, Cookie, and Set-Cookie. func NewClientTrace(ctx context.Context, opts ...ClientTraceOption) *httptrace.ClientTrace { ct := &clientTracer{ Context: ctx, activeHooks: make(map[string]context.Context), redactedHeaders: map[string]struct{}{ "authorization": {}, "www-authenticate": {}, "proxy-authenticate": {}, "proxy-authorization": {}, "cookie": {}, "set-cookie": {}, }, addHeaders: true, useSpans: true, } if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { ct.tracerProvider = span.TracerProvider() } else { ct.tracerProvider = otel.GetTracerProvider() } for _, opt := range opts { opt.apply(ct) } ct.tr = ct.tracerProvider.Tracer( "go.opentelemetry.io/otel/instrumentation/httptrace", trace.WithInstrumentationVersion(Version()), ) return &httptrace.ClientTrace{ GetConn: ct.getConn, GotConn: ct.gotConn, PutIdleConn: ct.putIdleConn, GotFirstResponseByte: ct.gotFirstResponseByte, Got100Continue: ct.got100Continue, Got1xxResponse: ct.got1xxResponse, DNSStart: ct.dnsStart, DNSDone: ct.dnsDone, ConnectStart: ct.connectStart, ConnectDone: ct.connectDone, TLSHandshakeStart: ct.tlsHandshakeStart, TLSHandshakeDone: ct.tlsHandshakeDone, WroteHeaderField: ct.wroteHeaderField, WroteHeaders: ct.wroteHeaders, Wait100Continue: ct.wait100Continue, WroteRequest: ct.wroteRequest, } } func (ct *clientTracer) start(hook, spanName string, attrs ...attribute.KeyValue) { if !ct.useSpans { if ct.root == nil { ct.root = trace.SpanFromContext(ct.Context) } ct.root.AddEvent(hook+".start", trace.WithAttributes(attrs...)) return } ct.mtx.Lock() defer ct.mtx.Unlock() if hookCtx, found := ct.activeHooks[hook]; !found { var sp trace.Span ct.activeHooks[hook], sp = ct.tr.Start(ct.getParentContext(hook), spanName, trace.WithAttributes(attrs...), trace.WithSpanKind(trace.SpanKindClient)) if ct.root == nil { ct.root = sp } } else { // end was called before start finished, add the start attributes and end the span here span := trace.SpanFromContext(hookCtx) span.SetAttributes(attrs...) span.End() delete(ct.activeHooks, hook) } } func (ct *clientTracer) end(hook string, err error, attrs ...attribute.KeyValue) { if !ct.useSpans { if err != nil { attrs = append(attrs, attribute.String(hook+".error", err.Error())) } ct.root.AddEvent(hook+".done", trace.WithAttributes(attrs...)) return } ct.mtx.Lock() defer ct.mtx.Unlock() if ctx, ok := ct.activeHooks[hook]; ok { span := trace.SpanFromContext(ctx) if err != nil { span.SetStatus(codes.Error, err.Error()) } span.SetAttributes(attrs...) span.End() delete(ct.activeHooks, hook) } else { // start is not finished before end is called. // Start a span here with the ending attributes that will be finished when start finishes. // Yes, it's backwards. v0v ctx, span := ct.tr.Start(ct.getParentContext(hook), hook, trace.WithAttributes(attrs...), trace.WithSpanKind(trace.SpanKindClient)) if err != nil { span.SetStatus(codes.Error, err.Error()) } ct.activeHooks[hook] = ctx } } func (ct *clientTracer) getParentContext(hook string) context.Context { ctx, ok := ct.activeHooks[parentHook(hook)] if !ok { return ct.Context } return ctx } func (ct *clientTracer) span(hook string) trace.Span { ct.mtx.Lock() defer ct.mtx.Unlock() if ctx, ok := ct.activeHooks[hook]; ok { return trace.SpanFromContext(ctx) } return nil } func (ct *clientTracer) getConn(host string) { ct.start("http.getconn", "http.getconn", semconv.NetHostName(host)) } func (ct *clientTracer) gotConn(info httptrace.GotConnInfo) { attrs := []attribute.KeyValue{ HTTPRemoteAddr.String(info.Conn.RemoteAddr().String()), HTTPLocalAddr.String(info.Conn.LocalAddr().String()), HTTPConnectionReused.Bool(info.Reused), HTTPConnectionWasIdle.Bool(info.WasIdle), } if info.WasIdle { attrs = append(attrs, HTTPConnectionIdleTime.String(info.IdleTime.String())) } ct.end("http.getconn", nil, attrs...) } func (ct *clientTracer) putIdleConn(err error) { ct.end("http.receive", err) } func (ct *clientTracer) gotFirstResponseByte() { ct.start("http.receive", "http.receive") } func (ct *clientTracer) dnsStart(info httptrace.DNSStartInfo) { ct.start("http.dns", "http.dns", semconv.NetHostName(info.Host)) } func (ct *clientTracer) dnsDone(info httptrace.DNSDoneInfo) { var addrs []string for _, netAddr := range info.Addrs { addrs = append(addrs, netAddr.String()) } ct.end("http.dns", info.Err, HTTPDNSAddrs.String(sliceToString(addrs))) } func (ct *clientTracer) connectStart(network, addr string) { ct.start("http.connect."+addr, "http.connect", HTTPRemoteAddr.String(addr), HTTPConnectionStartNetwork.String(network), ) } func (ct *clientTracer) connectDone(network, addr string, err error) { ct.end("http.connect."+addr, err, HTTPConnectionDoneAddr.String(addr), HTTPConnectionDoneNetwork.String(network), ) } func (ct *clientTracer) tlsHandshakeStart() { ct.start("http.tls", "http.tls") } func (ct *clientTracer) tlsHandshakeDone(_ tls.ConnectionState, err error) { ct.end("http.tls", err) } func (ct *clientTracer) wroteHeaderField(k string, v []string) { if ct.useSpans && ct.span("http.headers") == nil { ct.start("http.headers", "http.headers") } if !ct.addHeaders { return } k = strings.ToLower(k) value := sliceToString(v) if _, ok := ct.redactedHeaders[k]; ok { value = "****" } ct.root.SetAttributes(attribute.String("http.request.header."+k, value)) } func (ct *clientTracer) wroteHeaders() { if ct.useSpans && ct.span("http.headers") != nil { ct.end("http.headers", nil) } ct.start("http.send", "http.send") } func (ct *clientTracer) wroteRequest(info httptrace.WroteRequestInfo) { if info.Err != nil { ct.root.SetStatus(codes.Error, info.Err.Error()) } ct.end("http.send", info.Err) } func (ct *clientTracer) got100Continue() { span := ct.root if ct.useSpans { span = ct.span("http.receive") } span.AddEvent("GOT 100 - Continue") } func (ct *clientTracer) wait100Continue() { span := ct.root if ct.useSpans { span = ct.span("http.receive") } span.AddEvent("GOT 100 - Wait") } func (ct *clientTracer) got1xxResponse(code int, header textproto.MIMEHeader) error { span := ct.root if ct.useSpans { span = ct.span("http.receive") } span.AddEvent("GOT 1xx", trace.WithAttributes( HTTPStatus.Int(code), HTTPHeaderMIME.String(sm2s(header)), )) return nil } func sliceToString(value []string) string { if len(value) == 0 { return "undefined" } return strings.Join(value, ",") } func sm2s(value map[string][]string) string { var buf strings.Builder for k, v := range value { if buf.Len() != 0 { _, _ = buf.WriteString(",") } _, _ = buf.WriteString(k) _, _ = buf.WriteString("=") _, _ = buf.WriteString(sliceToString(v)) } return buf.String() } example/000077500000000000000000000000001443314701600350675ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptraceDockerfile000066400000000000000000000015731443314701600370670ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/net/http/httptrace/otelhttptrace/example FROM base AS example-httptrace-server RUN go install ./server/server.go CMD ["/go/bin/server"] FROM base AS example-httptrace-client RUN go install ./client/client.go CMD ["/go/bin/client"] README.md000066400000000000000000000013251443314701600363470ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example# HTTP Client-Server Example An HTTP client connects to an HTTP server. They both generate span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `http-server` and `http-client` services to run the example: ```sh docker-compose up --detach http-server http-client ``` The `http-client` service sends just one HTTP request to `http-server` and then exits. View the span generated to `stdout` in the logs: ```sh docker-compose logs http-client ``` View the span generated by `http-server` in the logs: ```sh docker-compose logs http-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` client/000077500000000000000000000000001443314701600363455ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/exampleclient.go000066400000000000000000000060411443314701600401530ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example/client// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "flag" "fmt" "io" "log" "net/http" "net/http/httptrace" "time" "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/baggage" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func initTracer() (*sdktrace.TracerProvider, error) { // Create stdout exporter to be able to retrieve // the collected spans. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // For the demonstration, use sdktrace.AlwaysSample sampler to sample all traces. // In a production application, use sdktrace.ProbabilitySampler with a desired probability. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() url := flag.String("server", "http://localhost:7777/hello", "server url") flag.Parse() client := http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} bag, _ := baggage.Parse("username=donuts") ctx := baggage.ContextWithBaggage(context.Background(), bag) var body []byte tr := otel.Tracer("example/client") err = func(ctx context.Context) error { ctx, span := tr.Start(ctx, "say hello", trace.WithAttributes(semconv.PeerService("ExampleService"))) defer span.End() ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx)) req, _ := http.NewRequestWithContext(ctx, "GET", *url, nil) fmt.Printf("Sending request...\n") res, err := client.Do(req) if err != nil { panic(err) } body, err = io.ReadAll(res.Body) _ = res.Body.Close() return err }(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Response Received: %s\n\n\n", body) fmt.Printf("Waiting for few seconds to export spans ...\n\n") time.Sleep(10 * time.Second) fmt.Printf("Inspect traces on stdout\n") } docker-compose.yml000066400000000000000000000020521443314701600405230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: http-server: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. target: example-httptrace-server networks: - example http-client: build: dockerfile: $PWD/Dockerfile context: ../../../../../.. target: example-httptrace-client command: ["/go/bin/client", "-server", "http://http-server:7777/hello"] networks: - example depends_on: - http-server networks: example: go.mod000066400000000000000000000015441443314701600362010ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/examplemodule go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/example go 1.18 replace ( go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace => ../ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../../../otelhttp ) require ( go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.42.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) go.sum000066400000000000000000000040411443314701600362210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/examplegithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= server/000077500000000000000000000000001443314701600363755ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/examplemodd.conf000066400000000000000000000014121443314701600401650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example/server# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # A basic modd.conf file for Go development. # Run go test on ALL modules on startup, and subsequently only on modules # containing changes. server.go { daemon +sigterm: go run server.go }server.go000066400000000000000000000051561443314701600402410ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/example/server// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "io" "log" "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/baggage" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func initTracer() (*sdktrace.TracerProvider, error) { // Create stdout exporter to be able to retrieve // the collected spans. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // For the demonstration, use sdktrace.AlwaysSample sampler to sample all traces. // In a production application, use sdktrace.ProbabilitySampler with a desired probability. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName("ExampleService"))), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() uk := attribute.Key("username") helloHandler := func(w http.ResponseWriter, req *http.Request) { ctx := req.Context() span := trace.SpanFromContext(ctx) bag := baggage.FromContext(ctx) span.AddEvent("handling this...", trace.WithAttributes(uk.String(bag.Member("username").Value()))) _, _ = io.WriteString(w, "Hello, world!\n") } otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello") http.Handle("/hello", otelHandler) err = http.ListenAndServe(":7777", nil) if err != nil { log.Fatal(err) } } go.mod000066400000000000000000000005571443314701600345510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptracemodule go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace go 1.19 require ( github.com/google/go-cmp v0.5.9 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect ) go.sum000066400000000000000000000026361443314701600345760ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptracegithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= httptrace.go000066400000000000000000000050371443314701600357660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttptrace // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" import ( "context" "net/http" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" "go.opentelemetry.io/otel/semconv/v1.17.0/netconv" "go.opentelemetry.io/otel/trace" ) // Option allows configuration of the httptrace Extract() // and Inject() functions. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } type config struct { propagators propagation.TextMapPropagator } func newConfig(opts []Option) *config { c := &config{propagators: otel.GetTextMapPropagator()} for _, o := range opts { o.apply(c) } return c } // WithPropagators sets the propagators to use for Extraction and Injection. func WithPropagators(props propagation.TextMapPropagator) Option { return optionFunc(func(c *config) { if props != nil { c.propagators = props } }) } // Extract returns the Attributes, Context Entries, and SpanContext that were encoded by Inject. func Extract(ctx context.Context, req *http.Request, opts ...Option) ([]attribute.KeyValue, baggage.Baggage, trace.SpanContext) { c := newConfig(opts) ctx = c.propagators.Extract(ctx, propagation.HeaderCarrier(req.Header)) attrs := append(httpconv.ServerRequest("", req), netconv.Transport("tcp")) if req.ContentLength > 0 { a := semconv.HTTPRequestContentLength(int(req.ContentLength)) attrs = append(attrs, a) } return attrs, baggage.FromContext(ctx), trace.SpanContextFromContext(ctx) } // Inject sets attributes, context entries, and span context from ctx into // the request. func Inject(ctx context.Context, req *http.Request, opts ...Option) { c := newConfig(opts) c.propagators.Inject(ctx, propagation.HeaderCarrier(req.Header)) } httptrace_test.go000066400000000000000000000120151443314701600370170ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttptrace_test import ( "context" "net/http" "net/http/httptest" "strings" "testing" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func TestRoundtrip(t *testing.T) { tr := trace.NewNoopTracerProvider().Tracer("httptrace/client") var expectedAttrs map[attribute.Key]string expectedCorrs := map[string]string{"foo": "bar"} props := otelhttptrace.WithPropagators(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) // Mock http server ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { attrs, corrs, span := otelhttptrace.Extract(r.Context(), r, props) actualAttrs := make(map[attribute.Key]string) for _, attr := range attrs { if attr.Key == semconv.NetSockPeerPortKey { // Peer port will be non-deterministic continue } actualAttrs[attr.Key] = attr.Value.Emit() } if diff := cmp.Diff(actualAttrs, expectedAttrs); diff != "" { t.Fatalf("[TestRoundtrip] Attributes are different: %v", diff) } actualCorrs := make(map[string]string) for _, corr := range corrs.Members() { actualCorrs[corr.Key()] = corr.Value() } if diff := cmp.Diff(actualCorrs, expectedCorrs); diff != "" { t.Fatalf("[TestRoundtrip] Correlations are different: %v", diff) } if !span.IsValid() { t.Fatalf("[TestRoundtrip] Invalid span extracted: %v", span) } _, err := w.Write([]byte("OK")) if err != nil { t.Fatal(err) } }), ) defer ts.Close() address := ts.Listener.Addr() hp := strings.Split(address.String(), ":") expectedAttrs = map[attribute.Key]string{ semconv.HTTPFlavorKey: "1.1", semconv.NetHostNameKey: hp[0], semconv.NetHostPortKey: hp[1], semconv.HTTPMethodKey: "GET", semconv.HTTPSchemeKey: "http", semconv.HTTPUserAgentKey: "Go-http-client/1.1", semconv.HTTPRequestContentLengthKey: "3", semconv.NetSockPeerAddrKey: hp[0], semconv.NetTransportKey: "ip_tcp", } client := ts.Client() ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) err := func(ctx context.Context) error { ctx, span := tr.Start(ctx, "test") defer span.End() bag, _ := baggage.Parse("foo=bar") ctx = baggage.ContextWithBaggage(ctx, bag) req, _ := http.NewRequest("GET", ts.URL, strings.NewReader("foo")) otelhttptrace.Inject(ctx, req, props) res, err := client.Do(req) if err != nil { t.Fatalf("Request failed: %s", err.Error()) } _ = res.Body.Close() return nil }(ctx) if err != nil { panic("unexpected error in http request: " + err.Error()) } } func TestSpecifyPropagators(t *testing.T) { tr := trace.NewNoopTracerProvider().Tracer("httptrace/client") expectedCorrs := map[string]string{"foo": "bar"} // Mock http server ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, corrs, span := otelhttptrace.Extract(r.Context(), r, otelhttptrace.WithPropagators(propagation.Baggage{})) actualCorrs := make(map[string]string) for _, corr := range corrs.Members() { actualCorrs[corr.Key()] = corr.Value() } if diff := cmp.Diff(actualCorrs, expectedCorrs); diff != "" { t.Fatalf("[TestRoundtrip] Correlations are different: %v", diff) } if span.IsValid() { t.Fatalf("[TestRoundtrip] valid span extracted, expected none: %v", span) } _, err := w.Write([]byte("OK")) if err != nil { t.Fatal(err) } }), ) defer ts.Close() client := ts.Client() err := func(ctx context.Context) error { ctx, span := tr.Start(ctx, "test") defer span.End() bag, _ := baggage.Parse("foo=bar") ctx = baggage.ContextWithBaggage(ctx, bag) req, _ := http.NewRequest("GET", ts.URL, nil) otelhttptrace.Inject(ctx, req, otelhttptrace.WithPropagators(propagation.Baggage{})) res, err := client.Do(req) if err != nil { t.Fatalf("Request failed: %s", err.Error()) } _ = res.Body.Close() return nil }(context.Background()) if err != nil { panic("unexpected error in http request: " + err.Error()) } } test/000077500000000000000000000000001443314701600344135ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptraceclienttrace_test.go000066400000000000000000000350141443314701600403010ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "net/http" "net/http/httptest" "net/http/httptrace" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" ) func getSpanFromRecorder(sr *tracetest.SpanRecorder, name string) (trace.ReadOnlySpan, bool) { for _, s := range sr.Ended() { if s.Name() == name { return s, true } } return nil, false } func getSpansFromRecorder(sr *tracetest.SpanRecorder, name string) []trace.ReadOnlySpan { var ret []trace.ReadOnlySpan for _, s := range sr.Ended() { if s.Name() == name { ret = append(ret, s) } } return ret } func TestHTTPRequestWithClientTrace(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) otel.SetTracerProvider(tp) tr := tp.Tracer("httptrace/client") // Mock http server ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { }), ) defer ts.Close() address := ts.Listener.Addr() client := ts.Client() err := func(ctx context.Context) error { ctx, span := tr.Start(ctx, "test") defer span.End() req, _ := http.NewRequest("GET", ts.URL, nil) _, req = otelhttptrace.W3C(ctx, req) res, err := client.Do(req) if err != nil { t.Fatalf("Request failed: %s", err.Error()) } _ = res.Body.Close() return nil }(context.Background()) if err != nil { panic("unexpected error in http request: " + err.Error()) } testLen := []struct { name string attributes []attribute.KeyValue parent string }{ { name: "http.connect", attributes: []attribute.KeyValue{ attribute.Key("http.conn.done.addr").String(address.String()), attribute.Key("http.conn.done.network").String("tcp"), attribute.Key("http.conn.start.network").String("tcp"), attribute.Key("http.remote").String(address.String()), }, parent: "http.getconn", }, { name: "http.getconn", attributes: []attribute.KeyValue{ attribute.Key("http.remote").String(address.String()), attribute.Key("net.host.name").String(address.String()), attribute.Key("http.conn.reused").Bool(false), attribute.Key("http.conn.wasidle").Bool(false), }, parent: "test", }, { name: "http.receive", parent: "test", }, { name: "http.headers", parent: "test", }, { name: "http.send", parent: "test", }, { name: "test", }, } for _, tl := range testLen { span, ok := getSpanFromRecorder(sr, tl.name) if !assert.True(t, ok) { continue } if tl.parent != "" { parent, ok := getSpanFromRecorder(sr, tl.parent) if assert.True(t, ok) { assert.Equal(t, span.Parent().SpanID(), parent.SpanContext().SpanID()) } } if len(tl.attributes) > 0 { attrs := span.Attributes() if tl.name == "http.getconn" { // http.local attribute uses a non-deterministic port. local := attribute.Key("http.local") var contains bool for i, a := range attrs { if a.Key == local { attrs = append(attrs[:i], attrs[i+1:]...) contains = true break } } assert.True(t, contains, "missing http.local attribute") } assert.ElementsMatch(t, tl.attributes, attrs) } } } func TestConcurrentConnectionStart(t *testing.T) { tts := []struct { name string run func(*httptrace.ClientTrace) }{ { name: "Open1Close1Open2Close2", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectDone("tcp", "127.0.0.1:3000", nil) ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectDone("tcp", "[::1]:3000", nil) }, }, { name: "Open2Close2Open1Close1", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectDone("tcp", "[::1]:3000", nil) ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectDone("tcp", "127.0.0.1:3000", nil) }, }, { name: "Open1Open2Close1Close2", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectDone("tcp", "127.0.0.1:3000", nil) ct.ConnectDone("tcp", "[::1]:3000", nil) }, }, { name: "Open1Open2Close2Close1", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectDone("tcp", "[::1]:3000", nil) ct.ConnectDone("tcp", "127.0.0.1:3000", nil) }, }, { name: "Open2Open1Close1Close2", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectDone("tcp", "127.0.0.1:3000", nil) ct.ConnectDone("tcp", "[::1]:3000", nil) }, }, { name: "Open2Open1Close2Close1", run: func(ct *httptrace.ClientTrace) { ct.ConnectStart("tcp", "[::1]:3000") ct.ConnectStart("tcp", "127.0.0.1:3000") ct.ConnectDone("tcp", "[::1]:3000", nil) ct.ConnectDone("tcp", "127.0.0.1:3000", nil) }, }, } expectedRemotes := []attribute.KeyValue{ attribute.String("http.remote", "127.0.0.1:3000"), attribute.String("http.conn.start.network", "tcp"), attribute.String("http.conn.done.addr", "127.0.0.1:3000"), attribute.String("http.conn.done.network", "tcp"), attribute.String("http.remote", "[::1]:3000"), attribute.String("http.conn.start.network", "tcp"), attribute.String("http.conn.done.addr", "[::1]:3000"), attribute.String("http.conn.done.network", "tcp"), } for _, tt := range tts { t.Run(tt.name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) otel.SetTracerProvider(tp) tt.run(otelhttptrace.NewClientTrace(context.Background())) spans := getSpansFromRecorder(sr, "http.connect") require.Len(t, spans, 2) var gotRemotes []attribute.KeyValue for _, span := range spans { gotRemotes = append(gotRemotes, span.Attributes()...) } assert.ElementsMatch(t, expectedRemotes, gotRemotes) }) } } func TestEndBeforeStartCreatesSpan(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) otel.SetTracerProvider(tp) ct := otelhttptrace.NewClientTrace(context.Background()) ct.DNSDone(httptrace.DNSDoneInfo{}) ct.DNSStart(httptrace.DNSStartInfo{Host: "example.com"}) name := "http.dns" spans := getSpansFromRecorder(sr, name) require.Len(t, spans, 1) } type clientTraceTestFixture struct { Address string URL string Client *http.Client SpanRecorder *tracetest.SpanRecorder } func prepareClientTraceTest(t *testing.T) clientTraceTestFixture { fixture := clientTraceTestFixture{} fixture.SpanRecorder = tracetest.NewSpanRecorder() otel.SetTracerProvider( trace.NewTracerProvider(trace.WithSpanProcessor(fixture.SpanRecorder)), ) ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { }), ) t.Cleanup(ts.Close) fixture.Client = ts.Client() fixture.URL = ts.URL fixture.Address = ts.Listener.Addr().String() return fixture } func TestWithoutSubSpans(t *testing.T) { fixture := prepareClientTraceTest(t) ctx := context.Background() ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), ), ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) resp, err := fixture.Client.Do(req) require.NoError(t, err) require.NoError(t, resp.Body.Close()) // no spans created because we were just using background context without span require.Len(t, fixture.SpanRecorder.Ended(), 0) // Start again with a "real" span in the context, now tracing should add // events and annotations. ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), ), ) req, err = http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) req.Header.Set("User-Agent", "oteltest/1.1") req.Header.Set("Authorization", "Bearer token123") require.NoError(t, err) resp, err = fixture.Client.Do(req) require.NoError(t, err) require.NoError(t, resp.Body.Close()) span.End() // we just have the one span we created require.Len(t, fixture.SpanRecorder.Ended(), 1) recSpan := fixture.SpanRecorder.Ended()[0] gotAttributes := recSpan.Attributes() require.Len(t, gotAttributes, 4) assert.Equal(t, []attribute.KeyValue{ attribute.Key("http.request.header.host").String(fixture.Address), attribute.Key("http.request.header.user-agent").String("oteltest/1.1"), attribute.Key("http.request.header.authorization").String("****"), attribute.Key("http.request.header.accept-encoding").String("gzip"), }, gotAttributes, ) type attrMap = map[attribute.Key]attribute.Value expectedEvents := []struct { Event string VerifyAttrs func(t *testing.T, got attrMap) }{ {"http.getconn.start", func(t *testing.T, got attrMap) { assert.Equal(t, attribute.StringValue(fixture.Address), got[attribute.Key("net.host.name")], ) }}, {"http.getconn.done", func(t *testing.T, got attrMap) { // value is dynamic, just verify we have the attribute assert.Contains(t, got, attribute.Key("http.conn.idletime")) assert.Equal(t, attribute.BoolValue(true), got[attribute.Key("http.conn.reused")], ) assert.Equal(t, attribute.BoolValue(true), got[attribute.Key("http.conn.wasidle")], ) assert.Equal(t, attribute.StringValue(fixture.Address), got[attribute.Key("http.remote")], ) // value is dynamic, just verify we have the attribute assert.Contains(t, got, attribute.Key("http.local")) }}, {"http.send.start", nil}, {"http.send.done", nil}, {"http.receive.start", nil}, {"http.receive.done", nil}, } require.Len(t, recSpan.Events(), len(expectedEvents)) for i, e := range recSpan.Events() { attrs := attrMap{} for _, a := range e.Attributes { attrs[a.Key] = a.Value } expected := expectedEvents[i] assert.Equal(t, expected.Event, e.Name) if expected.VerifyAttrs == nil { assert.Nil(t, e.Attributes, "Event %q has no attributes", e.Name) } else { e := e // make loop var lexical t.Run(e.Name, func(t *testing.T) { expected.VerifyAttrs(t, attrs) }) } } } func TestWithRedactedHeaders(t *testing.T) { fixture := prepareClientTraceTest(t) ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithRedactedHeaders("user-agent"), ), ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) resp, err := fixture.Client.Do(req) require.NoError(t, err) require.NoError(t, resp.Body.Close()) span.End() require.Len(t, fixture.SpanRecorder.Ended(), 1) recSpan := fixture.SpanRecorder.Ended()[0] gotAttributes := recSpan.Attributes() assert.Equal(t, []attribute.KeyValue{ attribute.Key("http.request.header.host").String(fixture.Address), attribute.Key("http.request.header.user-agent").String("****"), attribute.Key("http.request.header.accept-encoding").String("gzip"), }, gotAttributes, ) } func TestWithoutHeaders(t *testing.T) { fixture := prepareClientTraceTest(t) ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithoutHeaders(), ), ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) resp, err := fixture.Client.Do(req) require.NoError(t, err) require.NoError(t, resp.Body.Close()) span.End() require.Len(t, fixture.SpanRecorder.Ended(), 1) recSpan := fixture.SpanRecorder.Ended()[0] gotAttributes := recSpan.Attributes() require.Len(t, gotAttributes, 0) } func TestWithInsecureHeaders(t *testing.T) { fixture := prepareClientTraceTest(t) ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithInsecureHeaders(), ), ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) req.Header.Set("User-Agent", "oteltest/1.1") req.Header.Set("Authorization", "Bearer token123") require.NoError(t, err) resp, err := fixture.Client.Do(req) require.NoError(t, err) require.NoError(t, resp.Body.Close()) span.End() require.Len(t, fixture.SpanRecorder.Ended(), 1) recSpan := fixture.SpanRecorder.Ended()[0] gotAttributes := recSpan.Attributes() assert.Equal(t, []attribute.KeyValue{ attribute.Key("http.request.header.host").String(fixture.Address), attribute.Key("http.request.header.user-agent").String("oteltest/1.1"), attribute.Key("http.request.header.authorization").String("Bearer token123"), attribute.Key("http.request.header.accept-encoding").String("gzip"), }, gotAttributes, ) } func TestHTTPRequestWithTraceContext(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) // Mock http server ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { }), ) defer ts.Close() ctx, span := tp.Tracer("").Start(context.Background(), "parent_span") req, _ := http.NewRequest("GET", ts.URL, nil) req = req.WithContext(httptrace.WithClientTrace(req.Context(), otelhttptrace.NewClientTrace(ctx))) client := ts.Client() res, err := client.Do(req) require.NoError(t, err) _ = res.Body.Close() span.End() parent, ok := getSpanFromRecorder(sr, "parent_span") require.True(t, ok) getconn, ok := getSpanFromRecorder(sr, "http.getconn") require.True(t, ok) require.Equal(t, parent.SpanContext().TraceID(), getconn.SpanContext().TraceID()) require.Equal(t, parent.SpanContext().SpanID(), getconn.Parent().SpanID()) } doc.go000066400000000000000000000017051443314701600355120ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelhttptrace instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/test" go.mod000066400000000000000000000014071443314701600355230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/testmodule go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/test go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace => ../ go.sum000066400000000000000000000042761443314701600355570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/testgithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= version.go000066400000000000000000000020641443314701600364310ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/test" // Version is the current release version of the httptrace instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } version.go000066400000000000000000000020541443314701600354510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/httptrace/otelhttptrace// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttptrace // import "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" // Version is the current release version of the httptrace instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/000077500000000000000000000000001443314701600304765ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/client.go000066400000000000000000000045121443314701600323050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "context" "io" "net/http" "net/url" "strings" ) // DefaultClient is the default Client and is used by Get, Head, Post and PostForm. // Please be careful of intitialization order - for example, if you change // the global propagator, the DefaultClient might still be using the old one. var DefaultClient = &http.Client{Transport: NewTransport(http.DefaultTransport)} // Get is a convenient replacement for http.Get that adds a span around the request. func Get(ctx context.Context, targetURL string) (resp *http.Response, err error) { req, err := http.NewRequestWithContext(ctx, "GET", targetURL, nil) if err != nil { return nil, err } return DefaultClient.Do(req) } // Head is a convenient replacement for http.Head that adds a span around the request. func Head(ctx context.Context, targetURL string) (resp *http.Response, err error) { req, err := http.NewRequestWithContext(ctx, "HEAD", targetURL, nil) if err != nil { return nil, err } return DefaultClient.Do(req) } // Post is a convenient replacement for http.Post that adds a span around the request. func Post(ctx context.Context, targetURL, contentType string, body io.Reader) (resp *http.Response, err error) { req, err := http.NewRequestWithContext(ctx, "POST", targetURL, body) if err != nil { return nil, err } req.Header.Set("Content-Type", contentType) return DefaultClient.Do(req) } // PostForm is a convenient replacement for http.PostForm that adds a span around the request. func PostForm(ctx context.Context, targetURL string, data url.Values) (resp *http.Response, err error) { return Post(ctx, targetURL, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/common.go000066400000000000000000000041671443314701600323250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "net/http" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) // Attribute keys that can be added to a span. const ( ReadBytesKey = attribute.Key("http.read_bytes") // if anything was read from the request body, the total number of bytes read ReadErrorKey = attribute.Key("http.read_error") // If an error occurred while reading a request, the string of the error (io.EOF is not recorded) WroteBytesKey = attribute.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written WriteErrorKey = attribute.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded) ) // Server HTTP metrics. const ( RequestCount = "http.server.request_count" // Incoming request count total RequestContentLength = "http.server.request_content_length" // Incoming request bytes total ResponseContentLength = "http.server.response_content_length" // Incoming response bytes total ServerLatency = "http.server.duration" // Incoming end to end duration, microseconds ) // Filter is a predicate used to determine whether a given http.request should // be traced. A Filter must return true if the request should be traced. type Filter func(*http.Request) bool func newTracer(tp trace.TracerProvider) trace.Tracer { return tp.Tracer(instrumentationName, trace.WithInstrumentationVersion(Version())) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/config.go000066400000000000000000000144301443314701600322740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "context" "net/http" "net/http/httptrace" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const ( instrumentationName = "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) // config represents the configuration options available for the http.Handler // and http.Transport types. type config struct { ServerName string Tracer trace.Tracer Meter metric.Meter Propagators propagation.TextMapPropagator SpanStartOptions []trace.SpanStartOption PublicEndpoint bool PublicEndpointFn func(*http.Request) bool ReadEvent bool WriteEvent bool Filters []Filter SpanNameFormatter func(string, *http.Request) string ClientTrace func(context.Context) *httptrace.ClientTrace TracerProvider trace.TracerProvider MeterProvider metric.MeterProvider } // Option interface used for setting optional config properties. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // newConfig creates a new config struct and applies opts to it. func newConfig(opts ...Option) *config { c := &config{ Propagators: otel.GetTextMapPropagator(), MeterProvider: otel.GetMeterProvider(), } for _, opt := range opts { opt.apply(c) } // Tracer is only initialized if manually specified. Otherwise, can be passed with the tracing context. if c.TracerProvider != nil { c.Tracer = newTracer(c.TracerProvider) } c.Meter = c.MeterProvider.Meter( instrumentationName, metric.WithInstrumentationVersion(Version()), ) return c } // WithTracerProvider specifies a tracer provider to use for creating a tracer. // If none is specified, the global provider is used. func WithTracerProvider(provider trace.TracerProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.TracerProvider = provider } }) } // WithMeterProvider specifies a meter provider to use for creating a meter. // If none is specified, the global provider is used. func WithMeterProvider(provider metric.MeterProvider) Option { return optionFunc(func(cfg *config) { if provider != nil { cfg.MeterProvider = provider } }) } // WithPublicEndpoint configures the Handler to link the span with an incoming // span context. If this option is not provided, then the association is a child // association instead of a link. func WithPublicEndpoint() Option { return optionFunc(func(c *config) { c.PublicEndpoint = true }) } // WithPublicEndpointFn runs with every request, and allows conditionnally // configuring the Handler to link the span with an incoming span context. If // this option is not provided or returns false, then the association is a // child association instead of a link. // Note: WithPublicEndpoint takes precedence over WithPublicEndpointFn. func WithPublicEndpointFn(fn func(*http.Request) bool) Option { return optionFunc(func(c *config) { c.PublicEndpointFn = fn }) } // WithPropagators configures specific propagators. If this // option isn't specified, then the global TextMapPropagator is used. func WithPropagators(ps propagation.TextMapPropagator) Option { return optionFunc(func(c *config) { if ps != nil { c.Propagators = ps } }) } // WithSpanOptions configures an additional set of // trace.SpanOptions, which are applied to each new span. func WithSpanOptions(opts ...trace.SpanStartOption) Option { return optionFunc(func(c *config) { c.SpanStartOptions = append(c.SpanStartOptions, opts...) }) } // WithFilter adds a filter to the list of filters used by the handler. // If any filter indicates to exclude a request then the request will not be // traced. All filters must allow a request to be traced for a Span to be created. // If no filters are provided then all requests are traced. // Filters will be invoked for each processed request, it is advised to make them // simple and fast. func WithFilter(f Filter) Option { return optionFunc(func(c *config) { c.Filters = append(c.Filters, f) }) } type event int // Different types of events that can be recorded, see WithMessageEvents. const ( ReadEvents event = iota WriteEvents ) // WithMessageEvents configures the Handler to record the specified events // (span.AddEvent) on spans. By default only summary attributes are added at the // end of the request. // // Valid events are: // - ReadEvents: Record the number of bytes read after every http.Request.Body.Read // using the ReadBytesKey // - WriteEvents: Record the number of bytes written after every http.ResponeWriter.Write // using the WriteBytesKey func WithMessageEvents(events ...event) Option { return optionFunc(func(c *config) { for _, e := range events { switch e { case ReadEvents: c.ReadEvent = true case WriteEvents: c.WriteEvent = true } } }) } // WithSpanNameFormatter takes a function that will be called on every // request and the returned string will become the Span Name. func WithSpanNameFormatter(f func(operation string, r *http.Request) string) Option { return optionFunc(func(c *config) { c.SpanNameFormatter = f }) } // WithClientTrace takes a function that returns client trace instance that will be // applied to the requests sent through the otelhttp Transport. func WithClientTrace(f func(context.Context) *httptrace.ClientTrace) Option { return optionFunc(func(c *config) { c.ClientTrace = f }) } // WithServerName returns an Option that sets the name of the (virtual) server // handling requests. func WithServerName(server string) Option { return optionFunc(func(c *config) { c.ServerName = server }) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/doc.go000066400000000000000000000015441443314701600315760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package otelhttp provides an http.Handler and functions that are intended // to be used to add tracing by wrapping existing handlers (with Handler) and // routes WithRouteTag. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/000077500000000000000000000000001443314701600321315ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/Dockerfile000066400000000000000000000015421443314701600341250ustar00rootroot00000000000000# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.20-alpine AS base COPY . /src/ WORKDIR /src/instrumentation/net/http/otelhttp/example FROM base AS example-http-server RUN go install ./server/server.go CMD ["/go/bin/server"] FROM base AS example-http-client RUN go install ./client/client.go CMD ["/go/bin/client"] open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/README.md000066400000000000000000000013401443314701600334060ustar00rootroot00000000000000# HTTP Client-Server Example An HTTP client connects to an HTTP server. They both generate span information to `stdout`. These instructions expect you have [docker-compose](https://docs.docker.com/compose/) installed. Bring up the `http-server` and `http-client` services to run the example: ```sh docker-compose up --detach http-server http-client ``` The `http-client` service sends just one HTTP request to `http-server` and then exits. View the span and metric generated to `stdout` in the logs: ```sh docker-compose logs http-client ``` View the span generated by `http-server` in the logs: ```sh docker-compose logs http-server ``` Shut down the services when you are finished with the example: ```sh docker-compose down ``` open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/client/000077500000000000000000000000001443314701600334075ustar00rootroot00000000000000client.go000066400000000000000000000055601443314701600351430ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/client// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "flag" "fmt" "io" "log" "net/http" "time" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/baggage" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func initTracer() (*sdktrace.TracerProvider, error) { // Create stdout exporter to be able to retrieve // the collected spans. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // For the demonstration, use sdktrace.AlwaysSample sampler to sample all traces. // In a production application, use sdktrace.ProbabilitySampler with a desired probability. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, err } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() url := flag.String("server", "http://localhost:7777/hello", "server url") flag.Parse() client := http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} bag, _ := baggage.Parse("username=donuts") ctx := baggage.ContextWithBaggage(context.Background(), bag) var body []byte tr := otel.Tracer("example/client") err = func(ctx context.Context) error { ctx, span := tr.Start(ctx, "say hello", trace.WithAttributes(semconv.PeerService("ExampleService"))) defer span.End() req, _ := http.NewRequestWithContext(ctx, "GET", *url, nil) fmt.Printf("Sending request...\n") res, err := client.Do(req) if err != nil { panic(err) } body, err = io.ReadAll(res.Body) _ = res.Body.Close() return err }(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Response Received: %s\n\n\n", body) fmt.Printf("Waiting for few seconds to export spans ...\n\n") time.Sleep(10 * time.Second) fmt.Printf("Inspect traces on stdout\n") } docker-compose.yml000066400000000000000000000020321443314701600355040ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.7" services: http-server: build: dockerfile: $PWD/Dockerfile context: ../../../../.. target: example-http-server networks: - example http-client: build: dockerfile: $PWD/Dockerfile context: ../../../../.. target: example-http-client command: ["/go/bin/client", "-server", "http://http-server:7777/hello"] networks: - example depends_on: - http-server networks: example: open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/go.mod000066400000000000000000000014041443314701600332360ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/go.sum000066400000000000000000000047051443314701600332720ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 h1:fl2WmyenEf6LYYlfHAtCUEDyGcpwJNqD4dHGO7PVm4w= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0/go.mod h1:csyQxQ0UHHKVA8KApS7eUO/klMO5sd/av5CNZNU4O6w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/server/000077500000000000000000000000001443314701600334375ustar00rootroot00000000000000modd.conf000066400000000000000000000014121443314701600351500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/server# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # A basic modd.conf file for Go development. # Run go test on ALL modules on startup, and subsequently only on modules # containing changes. server.go { daemon +sigterm: go run server.go }server.go000066400000000000000000000062611443314701600352220ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/example/server// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "io" "log" "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func initTracer() (*sdktrace.TracerProvider, error) { // Create stdout exporter to be able to retrieve // the collected spans. exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) if err != nil { return nil, err } // For the demonstration, use sdktrace.AlwaysSample sampler to sample all traces. // In a production application, use sdktrace.ProbabilitySampler with a desired probability. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName("ExampleService"))), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, err } func initMeter() (*sdkmetric.MeterProvider, error) { exp, err := stdoutmetric.New() if err != nil { return nil, err } mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exp))) otel.SetMeterProvider(mp) return mp, nil } func main() { tp, err := initTracer() if err != nil { log.Fatal(err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() mp, err := initMeter() if err != nil { log.Fatal(err) } defer func() { if err := mp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down meter provider: %v", err) } }() uk := attribute.Key("username") helloHandler := func(w http.ResponseWriter, req *http.Request) { ctx := req.Context() span := trace.SpanFromContext(ctx) bag := baggage.FromContext(ctx) span.AddEvent("handling this...", trace.WithAttributes(uk.String(bag.Member("username").Value()))) _, _ = io.WriteString(w, "Hello, world!\n") } otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello") http.Handle("/hello", otelHandler) err = http.ListenAndServe(":7777", nil) if err != nil { log.Fatal(err) } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/filters/000077500000000000000000000000001443314701600321465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/filters/filters.go000066400000000000000000000066241443314701600341550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package filters provides a set of filters useful with the // otelhttp.WithFilter() option to control which inbound requests are traced. package filters // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/filters" import ( "net/http" "strings" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) // Any takes a list of Filters and returns a Filter that // returns true if any Filter in the list returns true. func Any(fs ...otelhttp.Filter) otelhttp.Filter { return func(r *http.Request) bool { for _, f := range fs { if f(r) { return true } } return false } } // All takes a list of Filters and returns a Filter that // returns true only if all Filters in the list return true. func All(fs ...otelhttp.Filter) otelhttp.Filter { return func(r *http.Request) bool { for _, f := range fs { if !f(r) { return false } } return true } } // None takes a list of Filters and returns a Filter that returns // true only if none of the Filters in the list return true. func None(fs ...otelhttp.Filter) otelhttp.Filter { return func(r *http.Request) bool { for _, f := range fs { if f(r) { return false } } return true } } // Not provides a convenience mechanism for inverting a Filter. func Not(f otelhttp.Filter) otelhttp.Filter { return func(r *http.Request) bool { return !f(r) } } // Hostname returns a Filter that returns true if the request's // hostname matches the provided string. func Hostname(h string) otelhttp.Filter { return func(r *http.Request) bool { return r.URL.Hostname() == h } } // Path returns a Filter that returns true if the request's // path matches the provided string. func Path(p string) otelhttp.Filter { return func(r *http.Request) bool { return r.URL.Path == p } } // PathPrefix returns a Filter that returns true if the request's // path starts with the provided string. func PathPrefix(p string) otelhttp.Filter { return func(r *http.Request) bool { return strings.HasPrefix(r.URL.Path, p) } } // Query returns a Filter that returns true if the request // includes a query parameter k with a value equal to v. func Query(k, v string) otelhttp.Filter { return func(r *http.Request) bool { for _, qv := range r.URL.Query()[k] { if v == qv { return true } } return false } } // QueryContains returns a Filter that returns true if the request // includes a query parameter k with a value that contains v. func QueryContains(k, v string) otelhttp.Filter { return func(r *http.Request) bool { for _, qv := range r.URL.Query()[k] { if strings.Contains(qv, v) { return true } } return false } } // Method returns a Filter that returns true if the request // method is equal to the provided value. func Method(m string) otelhttp.Filter { return func(r *http.Request) bool { return m == r.Method } } filters_test.go000066400000000000000000000160331443314701600351300ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/filters// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package filters import ( "net/http" "net/url" "testing" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) type scenario struct { name string filter otelhttp.Filter req *http.Request exp bool } func TestAny(t *testing.T) { for _, s := range []scenario{ { name: "no matching filters", filter: Any(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/boo", Host: "baz.bar:8080"}}, exp: false, }, { name: "one matching filter", filter: Any(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "baz.bar:8080"}}, exp: true, }, { name: "all matching filters", filter: Any(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "bar.baz:8080"}}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestAll(t *testing.T) { for _, s := range []scenario{ { name: "no matching filters", filter: All(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/boo", Host: "baz.bar:8080"}}, exp: false, }, { name: "one matching filter", filter: All(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "baz.bar:8080"}}, exp: false, }, { name: "all matching filters", filter: All(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "bar.baz:8080"}}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestNone(t *testing.T) { for _, s := range []scenario{ { name: "no matching filters", filter: None(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/boo", Host: "baz.bar:8080"}}, exp: true, }, { name: "one matching filter", filter: None(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "baz.bar:8080"}}, exp: false, }, { name: "all matching filters", filter: None(Path("/foo"), Hostname("bar.baz")), req: &http.Request{URL: &url.URL{Path: "/foo", Host: "bar.baz:8080"}}, exp: false, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestNot(t *testing.T) { req := &http.Request{URL: &url.URL{Path: "/foo", Host: "bar.baz:8080"}} filter := Path("/foo") if filter(req) == Not(filter)(req) { t.Error("Not filter should invert the result of the supplied filter") } } func TestPathPrefix(t *testing.T) { for _, s := range []scenario{ { name: "non-matching prefix", filter: PathPrefix("/foo"), req: &http.Request{URL: &url.URL{Path: "/boo/far", Host: "baz.bar:8080"}}, exp: false, }, { name: "matching prefix", filter: PathPrefix("/foo"), req: &http.Request{URL: &url.URL{Path: "/foo/bar", Host: "bar.baz:8080"}}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestMethod(t *testing.T) { for _, s := range []scenario{ { name: "non-matching method", filter: Method(http.MethodGet), req: &http.Request{Method: http.MethodHead, URL: &url.URL{Path: "/boo/far", Host: "baz.bar:8080"}}, exp: false, }, { name: "matching method", filter: Method(http.MethodGet), req: &http.Request{Method: http.MethodGet, URL: &url.URL{Path: "/boo/far", Host: "baz.bar:8080"}}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestQuery(t *testing.T) { matching, _ := url.Parse("http://bar.baz:8080/foo/bar?key=value") nonMatching, _ := url.Parse("http://bar.baz:8080/foo/bar?key=other") for _, s := range []scenario{ { name: "non-matching query parameter", filter: Query("key", "value"), req: &http.Request{Method: http.MethodHead, URL: nonMatching}, exp: false, }, { name: "matching query parameter", filter: Query("key", "value"), req: &http.Request{Method: http.MethodGet, URL: matching}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestQueryContains(t *testing.T) { matching, _ := url.Parse("http://bar.baz:8080/foo/bar?key=value") nonMatching, _ := url.Parse("http://bar.baz:8080/foo/bar?key=other") for _, s := range []scenario{ { name: "non-matching query parameter", filter: QueryContains("key", "alu"), req: &http.Request{Method: http.MethodHead, URL: nonMatching}, exp: false, }, { name: "matching query parameter", filter: QueryContains("key", "alu"), req: &http.Request{Method: http.MethodGet, URL: matching}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestHeader(t *testing.T) { matching := http.Header{} matching.Add("key", "value") nonMatching := http.Header{} nonMatching.Add("key", "other") for _, s := range []scenario{ { name: "non-matching query parameter", filter: Header("key", "value"), req: &http.Request{Method: http.MethodHead, Header: nonMatching}, exp: false, }, { name: "matching query parameter", filter: Header("key", "value"), req: &http.Request{Method: http.MethodGet, Header: matching}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } func TestHeaderContains(t *testing.T) { matching := http.Header{} matching.Add("key", "value") nonMatching := http.Header{} nonMatching.Add("key", "other") for _, s := range []scenario{ { name: "non-matching query parameter", filter: HeaderContains("key", "alu"), req: &http.Request{Method: http.MethodHead, Header: nonMatching}, exp: false, }, { name: "matching query parameter", filter: HeaderContains("key", "alu"), req: &http.Request{Method: http.MethodGet, Header: matching}, exp: true, }, } { res := s.filter(s.req) if s.exp != res { t.Errorf("Failed testing %q. Expected %t, got %t", s.name, s.exp, res) } } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/filters/header.go000066400000000000000000000027211443314701600337270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package filters // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/filters" import ( "net/http" "net/textproto" "strings" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) // Header returns a Filter that returns true if the request // includes a header k with a value equal to v. func Header(k, v string) otelhttp.Filter { return func(r *http.Request) bool { for _, hv := range r.Header[textproto.CanonicalMIMEHeaderKey(k)] { if v == hv { return true } } return false } } // HeaderContains returns a Filter that returns true if the request // includes a header k with a value that contains v. func HeaderContains(k, v string) otelhttp.Filter { return func(r *http.Request) bool { for _, hv := range r.Header[textproto.CanonicalMIMEHeaderKey(k)] { if strings.Contains(hv, v) { return true } } return false } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/go.mod000066400000000000000000000010021443314701600315750ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go 1.19 require ( github.com/felixge/httpsnoop v1.0.3 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/go.sum000066400000000000000000000040451443314701600316340ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/handler.go000066400000000000000000000202641443314701600324460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "io" "net/http" "time" "github.com/felixge/httpsnoop" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" "go.opentelemetry.io/otel/trace" ) var _ http.Handler = &Handler{} // Handler is http middleware that corresponds to the http.Handler interface and // is designed to wrap a http.Mux (or equivalent), while individual routes on // the mux are wrapped with WithRouteTag. A Handler will add various attributes // to the span using the attribute.Keys defined in this package. type Handler struct { operation string server string handler http.Handler tracer trace.Tracer meter metric.Meter propagators propagation.TextMapPropagator spanStartOptions []trace.SpanStartOption readEvent bool writeEvent bool filters []Filter spanNameFormatter func(string, *http.Request) string counters map[string]metric.Int64Counter valueRecorders map[string]metric.Float64Histogram publicEndpoint bool publicEndpointFn func(*http.Request) bool } func defaultHandlerFormatter(operation string, _ *http.Request) string { return operation } // NewHandler wraps the passed handler, functioning like middleware, in a span // named after the operation and with any provided Options. func NewHandler(handler http.Handler, operation string, opts ...Option) http.Handler { h := Handler{ handler: handler, operation: operation, } defaultOpts := []Option{ WithSpanOptions(trace.WithSpanKind(trace.SpanKindServer)), WithSpanNameFormatter(defaultHandlerFormatter), } c := newConfig(append(defaultOpts, opts...)...) h.configure(c) h.createMeasures() return &h } func (h *Handler) configure(c *config) { h.tracer = c.Tracer h.meter = c.Meter h.propagators = c.Propagators h.spanStartOptions = c.SpanStartOptions h.readEvent = c.ReadEvent h.writeEvent = c.WriteEvent h.filters = c.Filters h.spanNameFormatter = c.SpanNameFormatter h.publicEndpoint = c.PublicEndpoint h.publicEndpointFn = c.PublicEndpointFn h.server = c.ServerName } func handleErr(err error) { if err != nil { otel.Handle(err) } } func (h *Handler) createMeasures() { h.counters = make(map[string]metric.Int64Counter) h.valueRecorders = make(map[string]metric.Float64Histogram) requestBytesCounter, err := h.meter.Int64Counter(RequestContentLength) handleErr(err) responseBytesCounter, err := h.meter.Int64Counter(ResponseContentLength) handleErr(err) serverLatencyMeasure, err := h.meter.Float64Histogram(ServerLatency) handleErr(err) h.counters[RequestContentLength] = requestBytesCounter h.counters[ResponseContentLength] = responseBytesCounter h.valueRecorders[ServerLatency] = serverLatencyMeasure } // ServeHTTP serves HTTP requests (http.Handler). func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { requestStartTime := time.Now() for _, f := range h.filters { if !f(r) { // Simply pass through to the handler if a filter rejects the request h.handler.ServeHTTP(w, r) return } } ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) opts := []trace.SpanStartOption{ trace.WithAttributes(httpconv.ServerRequest(h.server, r)...), } if h.server != "" { hostAttr := semconv.NetHostName(h.server) opts = append(opts, trace.WithAttributes(hostAttr)) } opts = append(opts, h.spanStartOptions...) if h.publicEndpoint || (h.publicEndpointFn != nil && h.publicEndpointFn(r.WithContext(ctx))) { opts = append(opts, trace.WithNewRoot()) // Linking incoming span context if any for public endpoint. if s := trace.SpanContextFromContext(ctx); s.IsValid() && s.IsRemote() { opts = append(opts, trace.WithLinks(trace.Link{SpanContext: s})) } } tracer := h.tracer if tracer == nil { if span := trace.SpanFromContext(r.Context()); span.SpanContext().IsValid() { tracer = newTracer(span.TracerProvider()) } else { tracer = newTracer(otel.GetTracerProvider()) } } ctx, span := tracer.Start(ctx, h.spanNameFormatter(h.operation, r), opts...) defer span.End() readRecordFunc := func(int64) {} if h.readEvent { readRecordFunc = func(n int64) { span.AddEvent("read", trace.WithAttributes(ReadBytesKey.Int64(n))) } } var bw bodyWrapper // if request body is nil or NoBody, we don't want to mutate the body as it // will affect the identity of it in an unforeseeable way because we assert // ReadCloser fulfills a certain interface and it is indeed nil or NoBody. if r.Body != nil && r.Body != http.NoBody { bw.ReadCloser = r.Body bw.record = readRecordFunc r.Body = &bw } writeRecordFunc := func(int64) {} if h.writeEvent { writeRecordFunc = func(n int64) { span.AddEvent("write", trace.WithAttributes(WroteBytesKey.Int64(n))) } } rww := &respWriterWrapper{ ResponseWriter: w, record: writeRecordFunc, ctx: ctx, props: h.propagators, statusCode: http.StatusOK, // default status code in case the Handler doesn't write anything } // Wrap w to use our ResponseWriter methods while also exposing // other interfaces that w may implement (http.CloseNotifier, // http.Flusher, http.Hijacker, http.Pusher, io.ReaderFrom). w = httpsnoop.Wrap(w, httpsnoop.Hooks{ Header: func(httpsnoop.HeaderFunc) httpsnoop.HeaderFunc { return rww.Header }, Write: func(httpsnoop.WriteFunc) httpsnoop.WriteFunc { return rww.Write }, WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { return rww.WriteHeader }, }) labeler := &Labeler{} ctx = injectLabeler(ctx, labeler) h.handler.ServeHTTP(w, r.WithContext(ctx)) setAfterServeAttributes(span, bw.read, rww.written, rww.statusCode, bw.err, rww.err) // Add metrics attributes := append(labeler.Get(), httpconv.ServerRequest(h.server, r)...) if rww.statusCode > 0 { attributes = append(attributes, semconv.HTTPStatusCode(rww.statusCode)) } o := metric.WithAttributes(attributes...) h.counters[RequestContentLength].Add(ctx, bw.read, o) h.counters[ResponseContentLength].Add(ctx, rww.written, o) // Use floating point division here for higher precision (instead of Millisecond method). elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond) h.valueRecorders[ServerLatency].Record(ctx, elapsedTime, o) } func setAfterServeAttributes(span trace.Span, read, wrote int64, statusCode int, rerr, werr error) { attributes := []attribute.KeyValue{} // TODO: Consider adding an event after each read and write, possibly as an // option (defaulting to off), so as to not create needlessly verbose spans. if read > 0 { attributes = append(attributes, ReadBytesKey.Int64(read)) } if rerr != nil && rerr != io.EOF { attributes = append(attributes, ReadErrorKey.String(rerr.Error())) } if wrote > 0 { attributes = append(attributes, WroteBytesKey.Int64(wrote)) } if statusCode > 0 { attributes = append(attributes, semconv.HTTPStatusCode(statusCode)) } span.SetStatus(httpconv.ServerStatus(statusCode)) if werr != nil && werr != io.EOF { attributes = append(attributes, WriteErrorKey.String(werr.Error())) } span.SetAttributes(attributes...) } // WithRouteTag annotates a span with the provided route name using the // RouteKey Tag. func WithRouteTag(route string, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { span := trace.SpanFromContext(r.Context()) span.SetAttributes(semconv.HTTPRoute(route)) h.ServeHTTP(w, r) }) } handler_example_test.go000066400000000000000000000056141443314701600351430ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp_test import ( "context" "fmt" "io" "log" "net/http" "strings" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) func ExampleNewHandler() { /* curl -v -d "a painting" http://localhost:7777/hello/bob/ross ... * upload completely sent off: 10 out of 10 bytes < HTTP/1.1 200 OK < Traceparent: 00-76ae040ee5753f38edf1c2bd9bd128bd-dd394138cfd7a3dc-01 < Date: Fri, 04 Oct 2019 02:33:08 GMT < Content-Length: 45 < Content-Type: text/plain; charset=utf-8 < Hello, bob/ross! You sent me this: a painting */ figureOutName := func(ctx context.Context, s string) (string, error) { pp := strings.SplitN(s, "/", 2) var err error switch pp[1] { case "": err = fmt.Errorf("expected /hello/:name in %q", s) default: trace.SpanFromContext(ctx).SetAttributes(attribute.String("name", pp[1])) } return pp[1], err } var mux http.ServeMux mux.Handle("/hello/", otelhttp.WithRouteTag("/hello/:name", http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() labeler, _ := otelhttp.LabelerFromContext(ctx) var name string // Wrap another function in its own span if err := func(ctx context.Context) error { ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("exampleTracer").Start(ctx, "figureOutName") defer span.End() var err error name, err = figureOutName(ctx, r.URL.Path[1:]) return err }(ctx); err != nil { log.Println("error figuring out name: ", err) http.Error(w, err.Error(), http.StatusInternalServerError) labeler.Add(attribute.Bool("error", true)) return } d, err := io.ReadAll(r.Body) if err != nil { log.Println("error reading body: ", err) w.WriteHeader(http.StatusBadRequest) labeler.Add(attribute.Bool("error", true)) return } n, err := io.WriteString(w, "Hello, "+name+"!\nYou sent me this:\n"+string(d)) if err != nil { log.Printf("error writing reply after %d bytes: %s", n, err) labeler.Add(attribute.Bool("error", true)) } }), ), ) if err := http.ListenAndServe(":7777", otelhttp.NewHandler(&mux, "server", otelhttp.WithMessageEvents(otelhttp.ReadEvents, otelhttp.WriteEvents), ), ); err != nil { log.Fatal(err) } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/handler_test.go000066400000000000000000000053261443314701600335070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp_test import ( "io" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) func TestHandler(t *testing.T) { testCases := []struct { name string handler func(*testing.T) http.Handler requestBody io.Reader expectedStatusCode int }{ { name: "implements flusher", handler: func(t *testing.T) http.Handler { return otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Implements(t, (*http.Flusher)(nil), w) }), "test_handler", ) }, expectedStatusCode: http.StatusOK, }, { name: "succeeds", handler: func(t *testing.T) http.Handler { return otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.NotNil(t, r.Body) b, err := io.ReadAll(r.Body) assert.NoError(t, err) assert.Equal(t, "hello world", string(b)) }), "test_handler", ) }, requestBody: strings.NewReader("hello world"), expectedStatusCode: http.StatusOK, }, { name: "succeeds with a nil body", handler: func(t *testing.T) http.Handler { return otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Nil(t, r.Body) }), "test_handler", ) }, expectedStatusCode: http.StatusOK, }, { name: "succeeds with an http.NoBody", handler: func(t *testing.T) http.Handler { return otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.NoBody, r.Body) }), "test_handler", ) }, requestBody: http.NoBody, expectedStatusCode: http.StatusOK, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { r, err := http.NewRequest(http.MethodGet, "http://localhost/", tc.requestBody) require.NoError(t, err) rr := httptest.NewRecorder() tc.handler(t).ServeHTTP(rr, r) assert.Equal(t, tc.expectedStatusCode, rr.Result().StatusCode) }) } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/labeler.go000066400000000000000000000040311443314701600324310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "context" "sync" "go.opentelemetry.io/otel/attribute" ) // Labeler is used to allow instrumented HTTP handlers to add custom attributes to // the metrics recorded by the net/http instrumentation. type Labeler struct { mu sync.Mutex attributes []attribute.KeyValue } // Add attributes to a Labeler. func (l *Labeler) Add(ls ...attribute.KeyValue) { l.mu.Lock() defer l.mu.Unlock() l.attributes = append(l.attributes, ls...) } // Get returns a copy of the attributes added to the Labeler. func (l *Labeler) Get() []attribute.KeyValue { l.mu.Lock() defer l.mu.Unlock() ret := make([]attribute.KeyValue, len(l.attributes)) copy(ret, l.attributes) return ret } type labelerContextKeyType int const lablelerContextKey labelerContextKeyType = 0 func injectLabeler(ctx context.Context, l *Labeler) context.Context { return context.WithValue(ctx, lablelerContextKey, l) } // LabelerFromContext retrieves a Labeler instance from the provided context if // one is available. If no Labeler was found in the provided context a new, empty // Labeler is returned and the second return value is false. In this case it is // safe to use the Labeler but any attributes added to it will not be used. func LabelerFromContext(ctx context.Context) (*Labeler, bool) { l, ok := ctx.Value(lablelerContextKey).(*Labeler) if !ok { l = &Labeler{} } return l, ok } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test/000077500000000000000000000000001443314701600314555ustar00rootroot00000000000000client_test.go000066400000000000000000000060651443314701600342510ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "net/http" "net/http/httptest" "net/url" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" ) func TestConvenienceWrappers(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) orig := otelhttp.DefaultClient otelhttp.DefaultClient = &http.Client{ Transport: otelhttp.NewTransport( http.DefaultTransport, otelhttp.WithTracerProvider(provider), ), } defer func() { otelhttp.DefaultClient = orig }() content := []byte("Hello, world!") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := w.Write(content); err != nil { t.Fatal(err) } })) defer ts.Close() ctx := context.Background() res, err := otelhttp.Get(ctx, ts.URL) if err != nil { t.Fatal(err) } res.Body.Close() res, err = otelhttp.Head(ctx, ts.URL) if err != nil { t.Fatal(err) } res.Body.Close() res, err = otelhttp.Post(ctx, ts.URL, "text/plain", strings.NewReader("test")) if err != nil { t.Fatal(err) } res.Body.Close() form := make(url.Values) form.Set("foo", "bar") res, err = otelhttp.PostForm(ctx, ts.URL, form) if err != nil { t.Fatal(err) } res.Body.Close() spans := sr.Ended() require.Equal(t, 4, len(spans)) assert.Equal(t, "HTTP GET", spans[0].Name()) assert.Equal(t, "HTTP HEAD", spans[1].Name()) assert.Equal(t, "HTTP POST", spans[2].Name()) assert.Equal(t, "HTTP POST", spans[3].Name()) } func TestClientWithTraceContext(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(sr)) tracer := provider.Tracer("") ctx, span := tracer.Start(context.Background(), "http requests") content := []byte("Hello, world!") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := w.Write(content); err != nil { t.Fatal(err) } })) defer ts.Close() res, err := otelhttp.Get(ctx, ts.URL) if err != nil { t.Fatal(err) } res.Body.Close() span.End() spans := sr.Ended() require.Equal(t, 2, len(spans)) assert.Equal(t, "HTTP GET", spans[0].Name()) assert.Equal(t, "http requests", spans[1].Name()) assert.NotEmpty(t, spans[0].Parent().SpanID()) assert.Equal(t, spans[1].SpanContext().SpanID(), spans[0].Parent().SpanID()) } config_test.go000066400000000000000000000072311443314701600342340ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "io" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" ) func TestBasicFilter(t *testing.T) { rr := httptest.NewRecorder() spanRecorder := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(spanRecorder)) h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := io.WriteString(w, "hello world"); err != nil { t.Fatal(err) } }), "test_handler", otelhttp.WithTracerProvider(provider), otelhttp.WithFilter(func(r *http.Request) bool { return false }), ) r, err := http.NewRequest(http.MethodGet, "http://localhost/", nil) if err != nil { t.Fatal(err) } h.ServeHTTP(rr, r) if got, expected := rr.Result().StatusCode, http.StatusOK; got != expected { t.Fatalf("got %d, expected %d", got, expected) } if got := rr.Header().Get("Traceparent"); got != "" { t.Fatal("expected empty trace header") } if got, expected := len(spanRecorder.Ended()), 0; got != expected { t.Fatalf("got %d recorded spans, expected %d", got, expected) } d, err := io.ReadAll(rr.Result().Body) if err != nil { t.Fatal(err) } if got, expected := string(d), "hello world"; got != expected { t.Fatalf("got %q, expected %q", got, expected) } } func TestSpanNameFormatter(t *testing.T) { var testCases = []struct { name string formatter func(s string, r *http.Request) string operation string expected string }{ { name: "default handler formatter", formatter: func(operation string, _ *http.Request) string { return operation }, operation: "test_operation", expected: "test_operation", }, { name: "default transport formatter", formatter: func(_ string, r *http.Request) string { return "HTTP " + r.Method }, expected: "HTTP GET", }, { name: "custom formatter", formatter: func(s string, r *http.Request) string { return r.URL.Path }, operation: "", expected: "/hello", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { rr := httptest.NewRecorder() spanRecorder := tracetest.NewSpanRecorder() provider := trace.NewTracerProvider(trace.WithSpanProcessor(spanRecorder)) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if _, err := io.WriteString(w, "hello world"); err != nil { t.Fatal(err) } }) h := otelhttp.NewHandler( handler, tc.operation, otelhttp.WithTracerProvider(provider), otelhttp.WithSpanNameFormatter(tc.formatter), ) r, err := http.NewRequest(http.MethodGet, "http://localhost/hello", nil) if err != nil { t.Fatal(err) } h.ServeHTTP(rr, r) if got, expected := rr.Result().StatusCode, http.StatusOK; got != expected { t.Fatalf("got %d, expected %d", got, expected) } spans := spanRecorder.Ended() if assert.Len(t, spans, 1) { assert.Equal(t, tc.expected, spans[0].Name()) } }) } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test/doc.go000066400000000000000000000016611443314701600325550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package test validates the otelhttp instrumentation with the default SDK. This package is in a separate module from the instrumentation it tests to isolate the dependency of the default SDK and not impose this as a transitive dependency for users. */ package test // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/test" open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test/go.mod000066400000000000000000000014541443314701600325670ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/test go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => ../ open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test/go.sum000066400000000000000000000050541443314701600326140ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= handler_test.go000066400000000000000000000345761443314701600344200ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "fmt" "io" "net/http" "net/http/httptest" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" ) func assertScopeMetrics(t *testing.T, sm metricdata.ScopeMetrics, attrs attribute.Set) { assert.Equal(t, instrumentation.Scope{ Name: "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", Version: otelhttp.Version(), }, sm.Scope) require.Len(t, sm.Metrics, 3) want := metricdata.Metrics{ Name: "http.server.request_content_length", Data: metricdata.Sum[int64]{ DataPoints: []metricdata.DataPoint[int64]{{Attributes: attrs, Value: 0}}, Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, }, } metricdatatest.AssertEqual(t, want, sm.Metrics[0], metricdatatest.IgnoreTimestamp()) want = metricdata.Metrics{ Name: "http.server.response_content_length", Data: metricdata.Sum[int64]{ DataPoints: []metricdata.DataPoint[int64]{{Attributes: attrs, Value: 11}}, Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, }, } metricdatatest.AssertEqual(t, want, sm.Metrics[1], metricdatatest.IgnoreTimestamp()) // Duration value is not predictable. dur := sm.Metrics[2] assert.Equal(t, "http.server.duration", dur.Name) require.IsType(t, dur.Data, metricdata.Histogram[float64]{}) hist := dur.Data.(metricdata.Histogram[float64]) assert.Equal(t, metricdata.CumulativeTemporality, hist.Temporality) require.Len(t, hist.DataPoints, 1) dPt := hist.DataPoints[0] assert.Equal(t, attrs, dPt.Attributes, "attributes") assert.Equal(t, uint64(1), dPt.Count, "count") assert.Equal(t, []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}, dPt.Bounds, "bounds") } func TestHandlerBasics(t *testing.T) { rr := httptest.NewRecorder() spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(spanRecorder)) reader := metric.NewManualReader() meterProvider := metric.NewMeterProvider(metric.WithReader(reader)) h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { l, _ := otelhttp.LabelerFromContext(r.Context()) l.Add(attribute.String("test", "attribute")) if _, err := io.WriteString(w, "hello world"); err != nil { t.Fatal(err) } }), "test_handler", otelhttp.WithTracerProvider(provider), otelhttp.WithMeterProvider(meterProvider), otelhttp.WithPropagators(propagation.TraceContext{}), ) r, err := http.NewRequest(http.MethodGet, "http://localhost/", strings.NewReader("foo")) if err != nil { t.Fatal(err) } h.ServeHTTP(rr, r) rm := metricdata.ResourceMetrics{} err = reader.Collect(context.Background(), &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) attrs := attribute.NewSet( semconv.NetHostName(r.Host), semconv.HTTPSchemeHTTP, semconv.HTTPFlavorKey.String(fmt.Sprintf("1.%d", r.ProtoMinor)), semconv.HTTPMethod("GET"), attribute.String("test", "attribute"), semconv.HTTPStatusCode(200), ) assertScopeMetrics(t, rm.ScopeMetrics[0], attrs) if got, expected := rr.Result().StatusCode, http.StatusOK; got != expected { t.Fatalf("got %d, expected %d", got, expected) } spans := spanRecorder.Ended() if got, expected := len(spans), 1; got != expected { t.Fatalf("got %d spans, expected %d", got, expected) } if !spans[0].SpanContext().IsValid() { t.Fatalf("invalid span created: %#v", spans[0].SpanContext()) } d, err := io.ReadAll(rr.Result().Body) if err != nil { t.Fatal(err) } if got, expected := string(d), "hello world"; got != expected { t.Fatalf("got %q, expected %q", got, expected) } } func TestHandlerEmittedAttributes(t *testing.T) { testCases := []struct { name string handler func(http.ResponseWriter, *http.Request) attributes []attribute.KeyValue }{ { name: "With a success handler", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }, attributes: []attribute.KeyValue{ attribute.Int("http.status_code", http.StatusOK), }, }, { name: "With a failing handler", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) }, attributes: []attribute.KeyValue{ attribute.Int("http.status_code", http.StatusBadRequest), }, }, { name: "With an empty handler", handler: func(w http.ResponseWriter, r *http.Request) { }, attributes: []attribute.KeyValue{ attribute.Int("http.status_code", http.StatusOK), }, }, { name: "With persisting initial failing status in handler with multiple WriteHeader calls", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusOK) }, attributes: []attribute.KeyValue{ attribute.Int("http.status_code", http.StatusInternalServerError), }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) h := otelhttp.NewHandler( http.HandlerFunc(tc.handler), "test_handler", otelhttp.WithTracerProvider(provider), ) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) require.Len(t, sr.Ended(), 1, "should emit a span") attrs := sr.Ended()[0].Attributes() for _, a := range tc.attributes { assert.Contains(t, attrs, a) } }) } } type respWriteHeaderCounter struct { http.ResponseWriter headersWritten []int } func (rw *respWriteHeaderCounter) WriteHeader(statusCode int) { rw.headersWritten = append(rw.headersWritten, statusCode) rw.ResponseWriter.WriteHeader(statusCode) } func TestHandlerPropagateWriteHeaderCalls(t *testing.T) { testCases := []struct { name string handler func(http.ResponseWriter, *http.Request) expectHeadersWritten []int }{ { name: "With a success handler", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }, expectHeadersWritten: []int{http.StatusOK}, }, { name: "With a failing handler", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) }, expectHeadersWritten: []int{http.StatusBadRequest}, }, { name: "With an empty handler", handler: func(w http.ResponseWriter, r *http.Request) { }, expectHeadersWritten: nil, }, { name: "With calling WriteHeader twice", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusOK) }, expectHeadersWritten: []int{http.StatusInternalServerError, http.StatusOK}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) h := otelhttp.NewHandler( http.HandlerFunc(tc.handler), "test_handler", otelhttp.WithTracerProvider(provider), ) recorder := httptest.NewRecorder() rw := &respWriteHeaderCounter{ResponseWriter: recorder} h.ServeHTTP(rw, httptest.NewRequest("GET", "/", nil)) require.EqualValues(t, tc.expectHeadersWritten, rw.headersWritten, "should propagate all WriteHeader calls to underlying ResponseWriter") }) } } func TestHandlerRequestWithTraceContext(t *testing.T) { rr := httptest.NewRecorder() h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write([]byte("hello world")) require.NoError(t, err) }), "test_handler") r, err := http.NewRequest(http.MethodGet, "http://localhost/", nil) require.NoError(t, err) spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) tracer := provider.Tracer("") ctx, span := tracer.Start(context.Background(), "test_request") r = r.WithContext(ctx) h.ServeHTTP(rr, r) assert.Equal(t, http.StatusOK, rr.Result().StatusCode) span.End() spans := spanRecorder.Ended() require.Len(t, spans, 2) assert.Equal(t, "test_handler", spans[0].Name()) assert.Equal(t, "test_request", spans[1].Name()) assert.NotEmpty(t, spans[0].Parent().SpanID()) assert.Equal(t, spans[1].SpanContext().SpanID(), spans[0].Parent().SpanID()) } func TestWithPublicEndpoint(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) remoteSpan := trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, Remote: true, } prop := propagation.TraceContext{} h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s := trace.SpanFromContext(r.Context()) sc := s.SpanContext() // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) }), "test_handler", otelhttp.WithPublicEndpoint(), otelhttp.WithPropagators(prop), otelhttp.WithTracerProvider(provider), ) r, err := http.NewRequest(http.MethodGet, "http://localhost/", nil) require.NoError(t, err) sc := trace.NewSpanContext(remoteSpan) ctx := trace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r.Header)) rr := httptest.NewRecorder() h.ServeHTTP(rr, r) assert.Equal(t, http.StatusOK, rr.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, spanRecorder.ForceFlush(ctx)) done := spanRecorder.Ended() require.Len(t, done, 1) require.Len(t, done[0].Links(), 1, "should contain link") require.True(t, sc.Equal(done[0].Links()[0].SpanContext), "should link incoming span context") } func TestWithPublicEndpointFn(t *testing.T) { remoteSpan := trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, TraceFlags: trace.FlagsSampled, Remote: true, } prop := propagation.TraceContext{} for _, tt := range []struct { name string fn func(*http.Request) bool handlerAssert func(*testing.T, trace.SpanContext) spansAssert func(*testing.T, trace.SpanContext, []sdktrace.ReadOnlySpan) }{ { name: "with the method returning true", fn: func(r *http.Request) bool { return true }, handlerAssert: func(t *testing.T, sc trace.SpanContext) { // Should be with new root trace. assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.NotEqual(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, sc trace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 1, "should contain link") require.True(t, sc.Equal(spans[0].Links()[0].SpanContext), "should link incoming span context") }, }, { name: "with the method returning false", fn: func(r *http.Request) bool { return false }, handlerAssert: func(t *testing.T, sc trace.SpanContext) { // Should have remote span as parent assert.True(t, sc.IsValid()) assert.False(t, sc.IsRemote()) assert.Equal(t, remoteSpan.TraceID, sc.TraceID()) }, spansAssert: func(t *testing.T, _ trace.SpanContext, spans []sdktrace.ReadOnlySpan) { require.Len(t, spans, 1) require.Len(t, spans[0].Links(), 0, "should not contain link") }, }, } { t.Run(tt.name, func(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s := trace.SpanFromContext(r.Context()) tt.handlerAssert(t, s.SpanContext()) }), "test_handler", otelhttp.WithPublicEndpointFn(tt.fn), otelhttp.WithPropagators(prop), otelhttp.WithTracerProvider(provider), ) r, err := http.NewRequest(http.MethodGet, "http://localhost/", nil) require.NoError(t, err) sc := trace.NewSpanContext(remoteSpan) ctx := trace.ContextWithSpanContext(context.Background(), sc) prop.Inject(ctx, propagation.HeaderCarrier(r.Header)) rr := httptest.NewRecorder() h.ServeHTTP(rr, r) assert.Equal(t, http.StatusOK, rr.Result().StatusCode) // Recorded span should be linked with an incoming span context. assert.NoError(t, spanRecorder.ForceFlush(ctx)) spans := spanRecorder.Ended() tt.spansAssert(t, sc, spans) }) } } func TestSpanStatus(t *testing.T) { testCases := []struct { httpStatusCode int wantSpanStatus codes.Code }{ {http.StatusOK, codes.Unset}, {http.StatusBadRequest, codes.Unset}, {http.StatusInternalServerError, codes.Error}, } for _, tc := range testCases { t.Run(strconv.Itoa(tc.httpStatusCode), func(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider() provider.RegisterSpanProcessor(sr) h := otelhttp.NewHandler( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(tc.httpStatusCode) }), "test_handler", otelhttp.WithTracerProvider(provider), ) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)) require.Len(t, sr.Ended(), 1, "should emit a span") assert.Equal(t, sr.Ended()[0].Status().Code, tc.wantSpanStatus, "should only set Error status for HTTP statuses >= 500") }) } } transport_test.go000066400000000000000000000151221443314701600350210ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test import ( "context" "io" "net/http" "net/http/httptest" "net/http/httptrace" "runtime" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestTransportUsesFormatter(t *testing.T) { prop := propagation.TraceContext{} spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(spanRecorder)) content := []byte("Hello, world!") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := prop.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) span := trace.SpanContextFromContext(ctx) if !span.IsValid() { t.Fatalf("invalid span wrapping handler: %#v", span) } if _, err := w.Write(content); err != nil { t.Fatal(err) } })) defer ts.Close() r, err := http.NewRequest(http.MethodGet, ts.URL, nil) if err != nil { t.Fatal(err) } tr := otelhttp.NewTransport( http.DefaultTransport, otelhttp.WithTracerProvider(provider), otelhttp.WithPropagators(prop), ) c := http.Client{Transport: tr} res, err := c.Do(r) if err != nil { t.Fatal(err) } require.NoError(t, res.Body.Close()) spans := spanRecorder.Ended() spanName := spans[0].Name() expectedName := "HTTP GET" if spanName != expectedName { t.Fatalf("unexpected name: got %s, expected %s", spanName, expectedName) } } func TestTransportErrorStatus(t *testing.T) { // Prepare tracing stuff. spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(spanRecorder)) // Run a server and stop to make sure nothing is listening and force the error. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) server.Close() // Create our Transport and make request. tr := otelhttp.NewTransport( http.DefaultTransport, otelhttp.WithTracerProvider(provider), ) c := http.Client{Transport: tr} r, err := http.NewRequest(http.MethodGet, server.URL, nil) if err != nil { t.Fatal(err) } _, err = c.Do(r) if err == nil { t.Fatal("transport should have returned an error, it didn't") } // Check span. spans := spanRecorder.Ended() if len(spans) != 1 { t.Fatalf("expected 1 span; got: %d", len(spans)) } span := spans[0] if span.EndTime().IsZero() { t.Errorf("span should be ended; it isn't") } if got := span.Status().Code; got != codes.Error { t.Errorf("expected error status code on span; got: %q", got) } errSubstr := "connect: connection refused" if runtime.GOOS == "windows" { // tls.Dial returns an error that does not contain the substring "connection refused" // on Windows machines // // ref: "dial tcp 127.0.0.1:50115: connectex: No connection could be made because the target machine actively refused it." errSubstr = "No connection could be made because the target machine actively refused it" } if got := span.Status().Description; !strings.Contains(got, errSubstr) { t.Errorf("expected error status message on span; got: %q", got) } } func TestTransportRequestWithTraceContext(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) content := []byte("Hello, world!") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write(content) require.NoError(t, err) })) defer ts.Close() tracer := provider.Tracer("") ctx, span := tracer.Start(context.Background(), "test_span") r, err := http.NewRequest(http.MethodGet, ts.URL, nil) require.NoError(t, err) r = r.WithContext(ctx) tr := otelhttp.NewTransport( http.DefaultTransport, ) c := http.Client{Transport: tr} res, err := c.Do(r) require.NoError(t, err) span.End() body, err := io.ReadAll(res.Body) require.NoError(t, err) require.Equal(t, content, body) spans := spanRecorder.Ended() require.Len(t, spans, 2) assert.Equal(t, "test_span", spans[0].Name()) assert.Equal(t, "HTTP GET", spans[1].Name()) assert.NotEmpty(t, spans[1].Parent().SpanID()) assert.Equal(t, spans[0].SpanContext().SpanID(), spans[1].Parent().SpanID()) } func TestWithHTTPTrace(t *testing.T) { spanRecorder := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(spanRecorder), ) content := []byte("Hello, world!") ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write(content) require.NoError(t, err) })) defer ts.Close() tracer := provider.Tracer("") ctx, span := tracer.Start(context.Background(), "test_span") r, err := http.NewRequest(http.MethodGet, ts.URL, nil) require.NoError(t, err) r = r.WithContext(ctx) clientTracer := func(ctx context.Context) *httptrace.ClientTrace { var span trace.Span return &httptrace.ClientTrace{ GetConn: func(_ string) { _, span = trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "httptrace.GetConn") }, GotConn: func(_ httptrace.GotConnInfo) { if span != nil { span.End() } }, } } tr := otelhttp.NewTransport( http.DefaultTransport, otelhttp.WithClientTrace(clientTracer), ) c := http.Client{Transport: tr} res, err := c.Do(r) require.NoError(t, err) span.End() body, err := io.ReadAll(res.Body) require.NoError(t, err) require.Equal(t, content, body) spans := spanRecorder.Ended() require.Len(t, spans, 3) assert.Equal(t, "httptrace.GetConn", spans[0].Name()) assert.Equal(t, "test_span", spans[1].Name()) assert.Equal(t, "HTTP GET", spans[2].Name()) assert.NotEmpty(t, spans[0].Parent().SpanID()) assert.NotEmpty(t, spans[2].Parent().SpanID()) assert.Equal(t, spans[2].SpanContext().SpanID(), spans[0].Parent().SpanID()) assert.Equal(t, spans[1].SpanContext().SpanID(), spans[2].Parent().SpanID()) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/test/version.go000066400000000000000000000020441443314701600334710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package test // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/test" // Version is the current release version of the otelhttp instrumentation test module. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/transport.go000066400000000000000000000132041443314701600330610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "context" "io" "net/http" "net/http/httptrace" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/semconv/v1.17.0/httpconv" "go.opentelemetry.io/otel/trace" ) // Transport implements the http.RoundTripper interface and wraps // outbound HTTP(S) requests with a span. type Transport struct { rt http.RoundTripper tracer trace.Tracer propagators propagation.TextMapPropagator spanStartOptions []trace.SpanStartOption filters []Filter spanNameFormatter func(string, *http.Request) string clientTrace func(context.Context) *httptrace.ClientTrace } var _ http.RoundTripper = &Transport{} // NewTransport wraps the provided http.RoundTripper with one that // starts a span and injects the span context into the outbound request headers. // // If the provided http.RoundTripper is nil, http.DefaultTransport will be used // as the base http.RoundTripper. func NewTransport(base http.RoundTripper, opts ...Option) *Transport { if base == nil { base = http.DefaultTransport } t := Transport{ rt: base, } defaultOpts := []Option{ WithSpanOptions(trace.WithSpanKind(trace.SpanKindClient)), WithSpanNameFormatter(defaultTransportFormatter), } c := newConfig(append(defaultOpts, opts...)...) t.applyConfig(c) return &t } func (t *Transport) applyConfig(c *config) { t.tracer = c.Tracer t.propagators = c.Propagators t.spanStartOptions = c.SpanStartOptions t.filters = c.Filters t.spanNameFormatter = c.SpanNameFormatter t.clientTrace = c.ClientTrace } func defaultTransportFormatter(_ string, r *http.Request) string { return "HTTP " + r.Method } // RoundTrip creates a Span and propagates its context via the provided request's headers // before handing the request to the configured base RoundTripper. The created span will // end when the response body is closed or when a read from the body returns io.EOF. func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) { for _, f := range t.filters { if !f(r) { // Simply pass through to the base RoundTripper if a filter rejects the request return t.rt.RoundTrip(r) } } tracer := t.tracer if tracer == nil { if span := trace.SpanFromContext(r.Context()); span.SpanContext().IsValid() { tracer = newTracer(span.TracerProvider()) } else { tracer = newTracer(otel.GetTracerProvider()) } } opts := append([]trace.SpanStartOption{}, t.spanStartOptions...) // start with the configured options ctx, span := tracer.Start(r.Context(), t.spanNameFormatter("", r), opts...) if t.clientTrace != nil { ctx = httptrace.WithClientTrace(ctx, t.clientTrace(ctx)) } r = r.WithContext(ctx) span.SetAttributes(httpconv.ClientRequest(r)...) t.propagators.Inject(ctx, propagation.HeaderCarrier(r.Header)) res, err := t.rt.RoundTrip(r) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) span.End() return res, err } span.SetAttributes(httpconv.ClientResponse(res)...) span.SetStatus(httpconv.ClientStatus(res.StatusCode)) res.Body = newWrappedBody(span, res.Body) return res, err } // newWrappedBody returns a new and appropriately scoped *wrappedBody as an // io.ReadCloser. If the passed body implements io.Writer, the returned value // will implement io.ReadWriteCloser. func newWrappedBody(span trace.Span, body io.ReadCloser) io.ReadCloser { // The successful protocol switch responses will have a body that // implement an io.ReadWriteCloser. Ensure this interface type continues // to be satisfied if that is the case. if _, ok := body.(io.ReadWriteCloser); ok { return &wrappedBody{span: span, body: body} } // Remove the implementation of the io.ReadWriteCloser and only implement // the io.ReadCloser. return struct{ io.ReadCloser }{&wrappedBody{span: span, body: body}} } // wrappedBody is the response body type returned by the transport // instrumentation to complete a span. Errors encountered when using the // response body are recorded in span tracking the response. // // The span tracking the response is ended when this body is closed. // // If the response body implements the io.Writer interface (i.e. for // successful protocol switches), the wrapped body also will. type wrappedBody struct { span trace.Span body io.ReadCloser } var _ io.ReadWriteCloser = &wrappedBody{} func (wb *wrappedBody) Write(p []byte) (int, error) { // This will not panic given the guard in newWrappedBody. n, err := wb.body.(io.Writer).Write(p) if err != nil { wb.span.RecordError(err) wb.span.SetStatus(codes.Error, err.Error()) } return n, err } func (wb *wrappedBody) Read(b []byte) (int, error) { n, err := wb.body.Read(b) switch err { case nil: // nothing to do here but fall through to the return case io.EOF: wb.span.End() default: wb.span.RecordError(err) wb.span.SetStatus(codes.Error, err.Error()) } return n, err } func (wb *wrappedBody) Close() error { wb.span.End() if wb.body != nil { return wb.body.Close() } return nil } transport_example_test.go000066400000000000000000000015161443314701600355570ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp import ( "net/http" ) func ExampleNewTransport() { // Create an http.Client that uses the (ot)http.Transport // wrapped around the http.DefaultTransport _ = http.Client{ Transport: NewTransport(http.DefaultTransport), } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/transport_test.go000066400000000000000000000224741443314701600341310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp import ( "bytes" "context" "errors" "io" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func TestTransportFormatter(t *testing.T) { var httpMethods = []struct { name string method string expected string }{ { "GET method", http.MethodGet, "HTTP GET", }, { "HEAD method", http.MethodHead, "HTTP HEAD", }, { "POST method", http.MethodPost, "HTTP POST", }, { "PUT method", http.MethodPut, "HTTP PUT", }, { "PATCH method", http.MethodPatch, "HTTP PATCH", }, { "DELETE method", http.MethodDelete, "HTTP DELETE", }, { "CONNECT method", http.MethodConnect, "HTTP CONNECT", }, { "OPTIONS method", http.MethodOptions, "HTTP OPTIONS", }, { "TRACE method", http.MethodTrace, "HTTP TRACE", }, } for _, tc := range httpMethods { t.Run(tc.name, func(t *testing.T) { r, err := http.NewRequest(tc.method, "http://localhost/", nil) if err != nil { t.Fatal(err) } formattedName := "HTTP " + r.Method if formattedName != tc.expected { t.Fatalf("unexpected name: got %s, expected %s", formattedName, tc.expected) } }) } } func TestTransportBasics(t *testing.T) { prop := propagation.TraceContext{} content := []byte("Hello, world!") ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := prop.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) span := trace.SpanContextFromContext(ctx) if span.SpanID() != sc.SpanID() { t.Fatalf("testing remote SpanID: got %s, expected %s", span.SpanID(), sc.SpanID()) } if _, err := w.Write(content); err != nil { t.Fatal(err) } })) defer ts.Close() r, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) if err != nil { t.Fatal(err) } tr := NewTransport(http.DefaultTransport, WithPropagators(prop)) c := http.Client{Transport: tr} res, err := c.Do(r) if err != nil { t.Fatal(err) } body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } if !bytes.Equal(body, content) { t.Fatalf("unexpected content: got %s, expected %s", body, content) } } func TestNilTransport(t *testing.T) { prop := propagation.TraceContext{} content := []byte("Hello, world!") ctx := context.Background() sc := trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x01}, SpanID: trace.SpanID{0x01}, }) ctx = trace.ContextWithRemoteSpanContext(ctx, sc) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := prop.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) span := trace.SpanContextFromContext(ctx) if span.SpanID() != sc.SpanID() { t.Fatalf("testing remote SpanID: got %s, expected %s", span.SpanID(), sc.SpanID()) } if _, err := w.Write(content); err != nil { t.Fatal(err) } })) defer ts.Close() r, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) if err != nil { t.Fatal(err) } tr := NewTransport(nil, WithPropagators(prop)) c := http.Client{Transport: tr} res, err := c.Do(r) if err != nil { t.Fatal(err) } body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } if !bytes.Equal(body, content) { t.Fatalf("unexpected content: got %s, expected %s", body, content) } } const readSize = 42 type readCloser struct { readErr, closeErr error } func (rc readCloser) Read(p []byte) (n int, err error) { return readSize, rc.readErr } func (rc readCloser) Close() error { return rc.closeErr } type span struct { trace.Span ended bool recordedErr error statusCode codes.Code statusDesc string } func (s *span) End(...trace.SpanEndOption) { s.ended = true } func (s *span) RecordError(err error, _ ...trace.EventOption) { s.recordedErr = err } func (s *span) SetStatus(c codes.Code, d string) { s.statusCode, s.statusDesc = c, d } func (s *span) assert(t *testing.T, ended bool, err error, c codes.Code, d string) { // nolint: revive // ended is not a control flag. if ended { assert.True(t, s.ended, "not ended") } else { assert.False(t, s.ended, "ended") } if err == nil { assert.NoError(t, s.recordedErr, "recorded an error") } else { assert.Equal(t, err, s.recordedErr) } assert.Equal(t, c, s.statusCode, "status codes not equal") assert.Equal(t, d, s.statusDesc, "status description not equal") } func TestWrappedBodyRead(t *testing.T) { s := new(span) wb := &wrappedBody{span: trace.Span(s), body: readCloser{}} n, err := wb.Read([]byte{}) assert.Equal(t, readSize, n, "wrappedBody returned wrong bytes") assert.NoError(t, err) s.assert(t, false, nil, codes.Unset, "") } func TestWrappedBodyReadEOFError(t *testing.T) { s := new(span) wb := &wrappedBody{span: trace.Span(s), body: readCloser{readErr: io.EOF}} n, err := wb.Read([]byte{}) assert.Equal(t, readSize, n, "wrappedBody returned wrong bytes") assert.Equal(t, io.EOF, err) s.assert(t, true, nil, codes.Unset, "") } func TestWrappedBodyReadError(t *testing.T) { s := new(span) expectedErr := errors.New("test") wb := &wrappedBody{span: trace.Span(s), body: readCloser{readErr: expectedErr}} n, err := wb.Read([]byte{}) assert.Equal(t, readSize, n, "wrappedBody returned wrong bytes") assert.Equal(t, expectedErr, err) s.assert(t, false, expectedErr, codes.Error, expectedErr.Error()) } func TestWrappedBodyClose(t *testing.T) { s := new(span) wb := &wrappedBody{span: trace.Span(s), body: readCloser{}} assert.NoError(t, wb.Close()) s.assert(t, true, nil, codes.Unset, "") } func TestWrappedBodyClosePanic(t *testing.T) { s := new(span) var body io.ReadCloser wb := newWrappedBody(s, body) assert.NotPanics(t, func() { wb.Close() }, "nil body should not panic on close") } func TestWrappedBodyCloseError(t *testing.T) { s := new(span) expectedErr := errors.New("test") wb := &wrappedBody{span: trace.Span(s), body: readCloser{closeErr: expectedErr}} assert.Equal(t, expectedErr, wb.Close()) s.assert(t, true, nil, codes.Unset, "") } type readWriteCloser struct { readCloser writeErr error } const writeSize = 1 func (rwc readWriteCloser) Write([]byte) (int, error) { return writeSize, rwc.writeErr } func TestNewWrappedBodyReadWriteCloserImplementation(t *testing.T) { wb := newWrappedBody(nil, readWriteCloser{}) assert.Implements(t, (*io.ReadWriteCloser)(nil), wb) } func TestNewWrappedBodyReadCloserImplementation(t *testing.T) { wb := newWrappedBody(nil, readCloser{}) assert.Implements(t, (*io.ReadCloser)(nil), wb) _, ok := wb.(io.ReadWriteCloser) assert.False(t, ok, "wrappedBody should not implement io.ReadWriteCloser") } func TestWrappedBodyWrite(t *testing.T) { s := new(span) var rwc io.ReadWriteCloser assert.NotPanics(t, func() { rwc = newWrappedBody(s, readWriteCloser{}).(io.ReadWriteCloser) }) n, err := rwc.Write([]byte{}) assert.Equal(t, writeSize, n, "wrappedBody returned wrong bytes") assert.NoError(t, err) s.assert(t, false, nil, codes.Unset, "") } func TestWrappedBodyWriteError(t *testing.T) { s := new(span) expectedErr := errors.New("test") var rwc io.ReadWriteCloser assert.NotPanics(t, func() { rwc = newWrappedBody(s, readWriteCloser{ writeErr: expectedErr, }).(io.ReadWriteCloser) }) n, err := rwc.Write([]byte{}) assert.Equal(t, writeSize, n, "wrappedBody returned wrong bytes") assert.ErrorIs(t, err, expectedErr) s.assert(t, false, expectedErr, codes.Error, expectedErr.Error()) } func TestTransportProtocolSwitch(t *testing.T) { // This test validates the fix to #1329. // Simulate a "101 Switching Protocols" response from the test server. response := []byte(strings.Join([]string{ "HTTP/1.1 101 Switching Protocols", "Upgrade: WebSocket", "Connection: Upgrade", "", "", // Needed for extra CRLF. }, "\r\n")) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { conn, buf, err := w.(http.Hijacker).Hijack() require.NoError(t, err) _, err = buf.Write(response) require.NoError(t, err) require.NoError(t, buf.Flush()) require.NoError(t, conn.Close()) })) defer ts.Close() ctx := context.Background() r, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, http.NoBody) require.NoError(t, err) c := http.Client{Transport: NewTransport(http.DefaultTransport)} res, err := c.Do(r) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) assert.Implements(t, (*io.ReadWriteCloser)(nil), res.Body, "invalid body returned for protocol switch") } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/version.go000066400000000000000000000020271443314701600325130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" // Version is the current release version of the otelhttp instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/net/http/otelhttp/wrap.go000066400000000000000000000054131443314701600320010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" import ( "context" "io" "net/http" "go.opentelemetry.io/otel/propagation" ) var _ io.ReadCloser = &bodyWrapper{} // bodyWrapper wraps a http.Request.Body (an io.ReadCloser) to track the number // of bytes read and the last error. type bodyWrapper struct { io.ReadCloser record func(n int64) // must not be nil read int64 err error } func (w *bodyWrapper) Read(b []byte) (int, error) { n, err := w.ReadCloser.Read(b) n1 := int64(n) w.read += n1 w.err = err w.record(n1) return n, err } func (w *bodyWrapper) Close() error { return w.ReadCloser.Close() } var _ http.ResponseWriter = &respWriterWrapper{} // respWriterWrapper wraps a http.ResponseWriter in order to track the number of // bytes written, the last error, and to catch the first written statusCode. // TODO: The wrapped http.ResponseWriter doesn't implement any of the optional // types (http.Hijacker, http.Pusher, http.CloseNotifier, http.Flusher, etc) // that may be useful when using it in real life situations. type respWriterWrapper struct { http.ResponseWriter record func(n int64) // must not be nil // used to inject the header ctx context.Context props propagation.TextMapPropagator written int64 statusCode int err error wroteHeader bool } func (w *respWriterWrapper) Header() http.Header { return w.ResponseWriter.Header() } func (w *respWriterWrapper) Write(p []byte) (int, error) { if !w.wroteHeader { w.WriteHeader(http.StatusOK) } n, err := w.ResponseWriter.Write(p) n1 := int64(n) w.record(n1) w.written += n1 w.err = err return n, err } // WriteHeader persists initial statusCode for span attribution. // All calls to WriteHeader will be propagated to the underlying ResponseWriter // and will persist the statusCode from the first call. // Blocking consecutive calls to WriteHeader alters expected behavior and will // remove warning logs from net/http where developers will notice incorrect handler implementations. func (w *respWriterWrapper) WriteHeader(statusCode int) { if !w.wroteHeader { w.wroteHeader = true w.statusCode = statusCode } w.ResponseWriter.WriteHeader(statusCode) } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/000077500000000000000000000000001443314701600265515ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/doc.go000066400000000000000000000040241443314701600276450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package runtime implements the conventional runtime metrics specified by OpenTelemetry. // // The metric events produced are: // // runtime.go.cgo.calls - Number of cgo calls made by the current process // runtime.go.gc.count - Number of completed garbage collection cycles // runtime.go.gc.pause_ns (ns) Amount of nanoseconds in GC stop-the-world pauses // runtime.go.gc.pause_total_ns (ns) Cumulative nanoseconds in GC stop-the-world pauses since the program started // runtime.go.goroutines - Number of goroutines that currently exist // runtime.go.lookups - Number of pointer lookups performed by the runtime // runtime.go.mem.heap_alloc (bytes) Bytes of allocated heap objects // runtime.go.mem.heap_idle (bytes) Bytes in idle (unused) spans // runtime.go.mem.heap_inuse (bytes) Bytes in in-use spans // runtime.go.mem.heap_objects - Number of allocated heap objects // runtime.go.mem.heap_released (bytes) Bytes of idle spans whose physical memory has been returned to the OS // runtime.go.mem.heap_sys (bytes) Bytes of heap memory obtained from the OS // runtime.go.mem.live_objects - Number of live objects is the number of cumulative Mallocs - Frees // runtime.uptime (ms) Milliseconds since application was initialized package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime" open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/example/000077500000000000000000000000001443314701600302045ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/example/doc.go000066400000000000000000000012531443314701600313010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package main provides an example use of the runtime instrumentation. package main open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/example/go.mod000066400000000000000000000012021443314701600313050ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/runtime/example go 1.18 replace go.opentelemetry.io/contrib/instrumentation/runtime => ../ require ( go.opentelemetry.io/contrib/instrumentation/runtime v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/sdk/metric v0.39.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/example/go.sum000066400000000000000000000040631443314701600313420ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0 h1:fl2WmyenEf6LYYlfHAtCUEDyGcpwJNqD4dHGO7PVm4w= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.39.0/go.mod h1:csyQxQ0UHHKVA8KApS7eUO/klMO5sd/av5CNZNU4O6w= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/example/main.go000066400000000000000000000034301443314701600314570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build go1.18 // +build go1.18 package main import ( "context" "log" "os" "os/signal" "time" "go.opentelemetry.io/contrib/instrumentation/runtime" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" ) var res = resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName("runtime-instrumentation-example"), ) func main() { exp, err := stdoutmetric.New() if err != nil { log.Fatal(err) } // Register the exporter with an SDK via a periodic reader. read := metric.NewPeriodicReader(exp, metric.WithInterval(1*time.Second)) provider := metric.NewMeterProvider(metric.WithResource(res), metric.WithReader(read)) defer func() { err := provider.Shutdown(context.Background()) if err != nil { log.Fatal(err) } }() otel.SetMeterProvider(provider) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() log.Print("Starting runtime instrumentation:") err = runtime.Start(runtime.WithMinimumReadMemStatsInterval(time.Second)) if err != nil { log.Fatal(err) } <-ctx.Done() } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/go.mod000066400000000000000000000004651443314701600276640ustar00rootroot00000000000000module go.opentelemetry.io/contrib/instrumentation/runtime go 1.19 require ( go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/go.sum000066400000000000000000000025071443314701600277100ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/runtime.go000066400000000000000000000237671443314701600306020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime" import ( "context" goruntime "runtime" "sync" "time" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" ) // Runtime reports the work-in-progress conventional runtime metrics specified by OpenTelemetry. type runtime struct { config config meter metric.Meter } // config contains optional settings for reporting runtime metrics. type config struct { // MinimumReadMemStatsInterval sets the mininum interval // between calls to runtime.ReadMemStats(). Negative values // are ignored. MinimumReadMemStatsInterval time.Duration // MeterProvider sets the metric.MeterProvider. If nil, the global // Provider will be used. MeterProvider metric.MeterProvider } // Option supports configuring optional settings for runtime metrics. type Option interface { apply(*config) } // DefaultMinimumReadMemStatsInterval is the default minimum interval // between calls to runtime.ReadMemStats(). Use the // WithMinimumReadMemStatsInterval() option to modify this setting in // Start(). const DefaultMinimumReadMemStatsInterval time.Duration = 15 * time.Second // WithMinimumReadMemStatsInterval sets a minimum interval between calls to // runtime.ReadMemStats(), which is a relatively expensive call to make // frequently. This setting is ignored when `d` is negative. func WithMinimumReadMemStatsInterval(d time.Duration) Option { return minimumReadMemStatsIntervalOption(d) } type minimumReadMemStatsIntervalOption time.Duration func (o minimumReadMemStatsIntervalOption) apply(c *config) { if o >= 0 { c.MinimumReadMemStatsInterval = time.Duration(o) } } // WithMeterProvider sets the Metric implementation to use for // reporting. If this option is not used, the global metric.MeterProvider // will be used. `provider` must be non-nil. func WithMeterProvider(provider metric.MeterProvider) Option { return metricProviderOption{provider} } type metricProviderOption struct{ metric.MeterProvider } func (o metricProviderOption) apply(c *config) { if o.MeterProvider != nil { c.MeterProvider = o.MeterProvider } } // newConfig computes a config from the supplied Options. func newConfig(opts ...Option) config { c := config{ MeterProvider: otel.GetMeterProvider(), MinimumReadMemStatsInterval: DefaultMinimumReadMemStatsInterval, } for _, opt := range opts { opt.apply(&c) } return c } // Start initializes reporting of runtime metrics using the supplied config. func Start(opts ...Option) error { c := newConfig(opts...) if c.MinimumReadMemStatsInterval < 0 { c.MinimumReadMemStatsInterval = DefaultMinimumReadMemStatsInterval } if c.MeterProvider == nil { c.MeterProvider = otel.GetMeterProvider() } r := &runtime{ meter: c.MeterProvider.Meter( "go.opentelemetry.io/contrib/instrumentation/runtime", metric.WithInstrumentationVersion(Version()), ), config: c, } return r.register() } func (r *runtime) register() error { startTime := time.Now() uptime, err := r.meter.Int64ObservableCounter( "runtime.uptime", metric.WithUnit("ms"), metric.WithDescription("Milliseconds since application was initialized"), ) if err != nil { return err } goroutines, err := r.meter.Int64ObservableUpDownCounter( "process.runtime.go.goroutines", metric.WithDescription("Number of goroutines that currently exist"), ) if err != nil { return err } cgoCalls, err := r.meter.Int64ObservableUpDownCounter( "process.runtime.go.cgo.calls", metric.WithDescription("Number of cgo calls made by the current process"), ) if err != nil { return err } _, err = r.meter.RegisterCallback( func(ctx context.Context, o metric.Observer) error { o.ObserveInt64(uptime, time.Since(startTime).Milliseconds()) o.ObserveInt64(goroutines, int64(goruntime.NumGoroutine())) o.ObserveInt64(cgoCalls, goruntime.NumCgoCall()) return nil }, uptime, goroutines, cgoCalls, ) if err != nil { return err } return r.registerMemStats() } func (r *runtime) registerMemStats() error { var ( err error heapAlloc metric.Int64ObservableUpDownCounter heapIdle metric.Int64ObservableUpDownCounter heapInuse metric.Int64ObservableUpDownCounter heapObjects metric.Int64ObservableUpDownCounter heapReleased metric.Int64ObservableUpDownCounter heapSys metric.Int64ObservableUpDownCounter liveObjects metric.Int64ObservableUpDownCounter // TODO: is ptrLookups useful? I've not seen a value // other than zero. ptrLookups metric.Int64ObservableCounter gcCount metric.Int64ObservableCounter pauseTotalNs metric.Int64ObservableCounter gcPauseNs metric.Int64Histogram lastNumGC uint32 lastMemStats time.Time memStats goruntime.MemStats // lock prevents a race between batch observer and instrument registration. lock sync.Mutex ) lock.Lock() defer lock.Unlock() if heapAlloc, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_alloc", metric.WithUnit("By"), metric.WithDescription("Bytes of allocated heap objects"), ); err != nil { return err } if heapIdle, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_idle", metric.WithUnit("By"), metric.WithDescription("Bytes in idle (unused) spans"), ); err != nil { return err } if heapInuse, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_inuse", metric.WithUnit("By"), metric.WithDescription("Bytes in in-use spans"), ); err != nil { return err } if heapObjects, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_objects", metric.WithDescription("Number of allocated heap objects"), ); err != nil { return err } // FYI see https://github.com/golang/go/issues/32284 to help // understand the meaning of this value. if heapReleased, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_released", metric.WithUnit("By"), metric.WithDescription("Bytes of idle spans whose physical memory has been returned to the OS"), ); err != nil { return err } if heapSys, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.heap_sys", metric.WithUnit("By"), metric.WithDescription("Bytes of heap memory obtained from the OS"), ); err != nil { return err } if ptrLookups, err = r.meter.Int64ObservableCounter( "process.runtime.go.mem.lookups", metric.WithDescription("Number of pointer lookups performed by the runtime"), ); err != nil { return err } if liveObjects, err = r.meter.Int64ObservableUpDownCounter( "process.runtime.go.mem.live_objects", metric.WithDescription("Number of live objects is the number of cumulative Mallocs - Frees"), ); err != nil { return err } if gcCount, err = r.meter.Int64ObservableCounter( "process.runtime.go.gc.count", metric.WithDescription("Number of completed garbage collection cycles"), ); err != nil { return err } // Note that the following could be derived as a sum of // individual pauses, but we may lose individual pauses if the // observation interval is too slow. if pauseTotalNs, err = r.meter.Int64ObservableCounter( "process.runtime.go.gc.pause_total_ns", // TODO: nanoseconds units metric.WithDescription("Cumulative nanoseconds in GC stop-the-world pauses since the program started"), ); err != nil { return err } if gcPauseNs, err = r.meter.Int64Histogram( "process.runtime.go.gc.pause_ns", // TODO: nanoseconds units metric.WithDescription("Amount of nanoseconds in GC stop-the-world pauses"), ); err != nil { return err } _, err = r.meter.RegisterCallback( func(ctx context.Context, o metric.Observer) error { lock.Lock() defer lock.Unlock() now := time.Now() if now.Sub(lastMemStats) >= r.config.MinimumReadMemStatsInterval { goruntime.ReadMemStats(&memStats) lastMemStats = now } o.ObserveInt64(heapAlloc, int64(memStats.HeapAlloc)) o.ObserveInt64(heapIdle, int64(memStats.HeapIdle)) o.ObserveInt64(heapInuse, int64(memStats.HeapInuse)) o.ObserveInt64(heapObjects, int64(memStats.HeapObjects)) o.ObserveInt64(heapReleased, int64(memStats.HeapReleased)) o.ObserveInt64(heapSys, int64(memStats.HeapSys)) o.ObserveInt64(liveObjects, int64(memStats.Mallocs-memStats.Frees)) o.ObserveInt64(ptrLookups, int64(memStats.Lookups)) o.ObserveInt64(gcCount, int64(memStats.NumGC)) o.ObserveInt64(pauseTotalNs, int64(memStats.PauseTotalNs)) computeGCPauses(ctx, gcPauseNs, memStats.PauseNs[:], lastNumGC, memStats.NumGC) lastNumGC = memStats.NumGC return nil }, heapAlloc, heapIdle, heapInuse, heapObjects, heapReleased, heapSys, liveObjects, ptrLookups, gcCount, pauseTotalNs, ) if err != nil { return err } return nil } func computeGCPauses( ctx context.Context, recorder metric.Int64Histogram, circular []uint64, lastNumGC, currentNumGC uint32, ) { delta := int(int64(currentNumGC) - int64(lastNumGC)) if delta == 0 { return } if delta >= len(circular) { // There were > 256 collections, some may have been lost. recordGCPauses(ctx, recorder, circular) return } length := uint32(len(circular)) i := lastNumGC % length j := currentNumGC % length if j < i { // wrap around the circular buffer recordGCPauses(ctx, recorder, circular[i:]) recordGCPauses(ctx, recorder, circular[:j]) return } recordGCPauses(ctx, recorder, circular[i:j]) } func recordGCPauses( ctx context.Context, recorder metric.Int64Histogram, pauses []uint64, ) { for _, pause := range pauses { recorder.Record(ctx, int64(pause)) } } open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/runtime_test.go000066400000000000000000000016601443314701600316250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package runtime_test // TODO(#2757): Add integration tests for the runtime instrumentation. These // tests depend on // https://github.com/open-telemetry/opentelemetry-go/issues/3031 being // resolved. // // The added tests will depend on the metric SDK. Therefore, they should be // added to a sub-directory called "test" instead of this file. open-telemetry-opentelemetry-go-contrib-2135499/instrumentation/runtime/version.go000066400000000000000000000020131443314701600305610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime" // Version is the current release version of the runtime instrumentation. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/internal/000077500000000000000000000000001443314701600234375ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/internal/util/000077500000000000000000000000001443314701600244145ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/internal/util/testutil.go000066400000000000000000000017721443314701600266270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package util // import "go.opentelemetry.io/contrib/internal/util" import ( "fmt" "os" ) func IntegrationShouldRun(name string) { if val, ok := os.LookupEnv("INTEGRATION"); !ok || val != name { fmt.Println( "--- SKIP: to enable integration test, set the INTEGRATION environment variable", "to", fmt.Sprintf("\"%s\"", name), ) os.Exit(0) //nolint revive // Signal test was successfully skipped. } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/000077500000000000000000000000001443314701600241645ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/000077500000000000000000000000001443314701600260355ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/doc.go000066400000000000000000000023201443314701600271260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package autoprop provides an OpenTelemetry TextMapPropagator creation // function. The OpenTelemetry specification states that the default // TextMapPropagator needs to be a no-operation implementation. The // opentelemetry-go project adheres to this requirement. However, for systems // that perform propagation this default is not ideal. This package provides a // TextMapPropagator with useful defaults (a combined TraceContext and Baggage // TextMapPropagator), and supports environment overrides using the // OTEL_PROPAGATORS environment variable. package autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop" open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/example_test.go000066400000000000000000000070071443314701600310620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package autoprop_test import ( "fmt" "os" "sort" "go.opentelemetry.io/contrib/propagators/autoprop" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" ) func ExampleNewTextMapPropagator() { // NewTextMapPropagator returns a TraceContext and Baggage propagator by // default. The response of this function can be directly registered with // the go.opentelemetry.io/otel package. otel.SetTextMapPropagator(autoprop.NewTextMapPropagator()) fields := otel.GetTextMapPropagator().Fields() sort.Strings(fields) fmt.Println(fields) // Output: [baggage traceparent tracestate] } func ExampleNewTextMapPropagator_arguments() { // NewTextMapPropagator behaves the same as the // NewCompositeTextMapPropagator function in the // go.opentelemetry.io/otel/propagation package when TextMapPropagator are // passed as arguments. fields := autoprop.NewTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, b3.New(), ).Fields() sort.Strings(fields) fmt.Println(fields) // Output: [baggage traceparent tracestate x-b3-flags x-b3-sampled x-b3-spanid x-b3-traceid] } func ExampleNewTextMapPropagator_environment() { // Propagators set for the OTEL_PROPAGATORS environment variable take // precedence and will override any arguments passed to // NewTextMapPropagator. _ = os.Setenv("OTEL_PROPAGATORS", "b3,baggage") // Returns only a B3 and Baggage TextMapPropagator (i.e. does not include // TraceContext). fields := autoprop.NewTextMapPropagator(propagation.TraceContext{}).Fields() sort.Strings(fields) fmt.Println(fields) // Output: [baggage x-b3-flags x-b3-sampled x-b3-spanid x-b3-traceid] } type myTextMapPropagator struct{ propagation.TextMapPropagator } func (myTextMapPropagator) Fields() []string { return []string{"my-header-val"} } func ExampleRegisterTextMapPropagator() { // To use your own or a 3rd-party exporter via the OTEL_PROPAGATORS // environment variable, it needs to be registered prior to calling // NewTextMapPropagator. autoprop.RegisterTextMapPropagator("custom-prop", myTextMapPropagator{}) _ = os.Setenv("OTEL_PROPAGATORS", "custom-prop") fmt.Println(autoprop.NewTextMapPropagator().Fields()) // Output: [my-header-val] } func ExampleGetTextMapPropagator() { prop, err := autoprop.TextMapPropagator("b3", "baggage") if err != nil { // Handle error appropriately. panic(err) } fields := prop.Fields() sort.Strings(fields) fmt.Println(fields) // Output: [baggage x-b3-flags x-b3-sampled x-b3-spanid x-b3-traceid] } func ExampleGetTextMapPropagator_custom() { // To use your own or a 3rd-party exporter it needs to be registered prior // to calling GetTextMapPropagator. autoprop.RegisterTextMapPropagator("custom-get-prop", myTextMapPropagator{}) prop, err := autoprop.TextMapPropagator("custom-get-prop") if err != nil { // Handle error appropriately. panic(err) } fmt.Println(prop.Fields()) // Output: [my-header-val] } open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/go.mod000066400000000000000000000020741443314701600271460ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/autoprop go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/contrib/propagators/aws v1.17.0 go.opentelemetry.io/contrib/propagators/b3 v1.17.0 go.opentelemetry.io/contrib/propagators/jaeger v1.17.0 go.opentelemetry.io/contrib/propagators/ot v1.17.0 go.opentelemetry.io/otel v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/contrib/propagators/jaeger => ../jaeger replace go.opentelemetry.io/contrib/propagators/b3 => ../b3 replace go.opentelemetry.io/contrib/propagators/aws => ../aws replace go.opentelemetry.io/contrib/propagators/ot => ../ot open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/go.sum000066400000000000000000000045371443314701600272010ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/propagator.go000066400000000000000000000066021443314701600305460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop" import ( "errors" "os" "strings" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" ) // otelPropagatorsEnvKey is the environment variable name identifying // propagators to use. const otelPropagatorsEnvKey = "OTEL_PROPAGATORS" // NewTextMapPropagator returns a new TextMapPropagator composited by props or // one defined by the OTEL_PROPAGATORS environment variable. The // TextMapPropagator defined by OTEL_PROPAGATORS, if set, will take precedence // to the once composited by props. // // The propagators supported with the OTEL_PROPAGATORS environment variable by // default are: tracecontext, baggage, b3, b3multi, jaeger, xray, ottrace, and // none. Each of these values, and their combination, are supported in // conformance with the OpenTelemetry specification. See // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration // for more information. // // The supported environment variable propagators can be extended to include // custom 3rd-party TextMapPropagator. See the RegisterTextMapPropagator // function for more information. // // If OTEL_PROPAGATORS is not defined and props is no provided, the returned // TextMapPropagator will be a composite of the TraceContext and Baggage // propagators. func NewTextMapPropagator(props ...propagation.TextMapPropagator) propagation.TextMapPropagator { // Environment variable defined propagator has precedence over arguments. envProp, err := parseEnv() if err != nil { // Communicate to the user their supplied value will not be used. otel.Handle(err) } if envProp != nil { return envProp } switch len(props) { case 0: // Default to TraceContext and Baggage. return propagation.NewCompositeTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, ) case 1: // Do not add overhead with a composite propagator wrapping a single // propagator, return it directly. return props[0] default: return propagation.NewCompositeTextMapPropagator(props...) } } // errUnknownPropagator is returned when an unknown propagator name is used in // the OTEL_PROPAGATORS environment variable. var errUnknownPropagator = errors.New("unknown propagator") // parseEnv returns the composite TextMapPropagators defined by the // OTEL_PROPAGATORS environment variable. A nil TextMapPropagator is returned // if no propagator is defined for the environment variable. A no-op // TextMapPropagator will be returned if "none" is defined anywhere in the // environment variable. func parseEnv() (propagation.TextMapPropagator, error) { propStrs, defined := os.LookupEnv(otelPropagatorsEnvKey) if !defined { return nil, nil } return TextMapPropagator(strings.Split(propStrs, ",")...) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/propagator_test.go000066400000000000000000000034501443314701600316030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package autoprop import ( "context" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" ) type handler struct { err error } func (h *handler) Handle(err error) { h.err = err } func TestNewTextMapPropagatorInvalidEnvVal(t *testing.T) { h := &handler{} otel.SetErrorHandler(h) const name = "invalid-name" t.Setenv(otelPropagatorsEnvKey, name) _ = NewTextMapPropagator() assert.ErrorIs(t, h.err, errUnknownPropagator) } func TestNewTextMapPropagatorDefault(t *testing.T) { expect := []string{"traceparent", "tracestate", "baggage"} assert.ElementsMatch(t, expect, NewTextMapPropagator().Fields()) } type ptrNoop struct{} func (*ptrNoop) Inject(context.Context, propagation.TextMapCarrier) {} func (*ptrNoop) Extract(context.Context, propagation.TextMapCarrier) context.Context { return context.Background() } func (*ptrNoop) Fields() []string { return nil } func TestNewTextMapPropagatorSingleNoOverhead(t *testing.T) { p := &ptrNoop{} assert.Same(t, p, NewTextMapPropagator(p)) } func TestNewTextMapPropagatorMultiEnvNone(t *testing.T) { t.Setenv(otelPropagatorsEnvKey, "b3,none,tracecontext") assert.Equal(t, noop, NewTextMapPropagator()) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/registry.go000066400000000000000000000126471443314701600302460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop" import ( "errors" "fmt" "strings" "sync" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/contrib/propagators/jaeger" "go.opentelemetry.io/contrib/propagators/ot" "go.opentelemetry.io/otel/propagation" ) // none is the special "propagator" name that means no propagator shall be // configured. const none = "none" // propagators is the registry of TextMapPropagators registered with this // package. It includes all the OpenTelemetry defaults at startup. var propagators = ®istry{ names: map[string]propagation.TextMapPropagator{ // W3C Trace Context. "tracecontext": propagation.TraceContext{}, // W3C Baggage. "baggage": propagation.Baggage{}, // B3 single-header format. "b3": b3.New(), // B3 multi-header format. "b3multi": b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader)), // Jaeger. "jaeger": jaeger.Jaeger{}, // AWS X-Ray. "xray": xray.Propagator{}, // OpenTracing Trace. "ottrace": ot.OT{}, // No-op TextMapPropagator. none: propagation.NewCompositeTextMapPropagator(), }, } // registry maintains a map of propagator names to TextMapPropagator // implementations that is safe for concurrent use by multiple goroutines // without additional locking or coordination. type registry struct { mu sync.Mutex names map[string]propagation.TextMapPropagator } // load returns the value stored in the registry index for a key, or nil if no // value is present. The ok result indicates whether value was found in the // index. func (r *registry) load(key string) (p propagation.TextMapPropagator, ok bool) { r.mu.Lock() p, ok = r.names[key] r.mu.Unlock() return p, ok } var errDupReg = errors.New("duplicate registration") // store sets the value for a key if is not already in the registry. errDupReg // is returned if the registry already contains key. func (r *registry) store(key string, value propagation.TextMapPropagator) error { r.mu.Lock() defer r.mu.Unlock() if r.names == nil { r.names = map[string]propagation.TextMapPropagator{key: value} return nil } if _, ok := r.names[key]; ok { return fmt.Errorf("%w: %q", errDupReg, key) } r.names[key] = value return nil } // drop removes key from the registry if it exists, otherwise nothing. func (r *registry) drop(key string) { r.mu.Lock() delete(r.names, key) r.mu.Unlock() } // RegisterTextMapPropagator sets the TextMapPropagator p to be used when the // OTEL_PROPAGATORS environment variable contains the propagator name. This // will panic if name has already been registered or is a default // (tracecontext, baggage, b3, b3multi, jaeger, xray, or ottrace). func RegisterTextMapPropagator(name string, p propagation.TextMapPropagator) { if err := propagators.store(name, p); err != nil { // envRegistry.store will return errDupReg if name is already // registered. Panic here so the user is made aware of the duplicate // registration, which could be done by malicious code trying to // intercept cross-cutting concerns. // // Panic for all other errors as well. At this point there should not // be any other errors returned from the store operation. If there // are, alert the developer that adding them as soon as possible that // they need to be handled here. panic(err) } } // TextMapPropagator returns a TextMapPropagator composed from the // passed names of registered TextMapPropagators. Each name must match an // already registered TextMapPropagator (see the RegisterTextMapPropagator // function for more information) or a default (tracecontext, baggage, b3, // b3multi, jaeger, xray, or ottrace). // // If "none" is included in the arguments, or no names are provided, the // returned TextMapPropagator will be a no-operation implementation. // // An error is returned for any un-registered names. The remaining, known, // names will be used to compose a TextMapPropagator that is returned with the // error. func TextMapPropagator(names ...string) (propagation.TextMapPropagator, error) { var ( props []propagation.TextMapPropagator unknown []string ) for _, name := range names { if name == none { // If "none" is passed in combination with any other propagator, // the result still needs to be a no-op propagator. Therefore, // short-circuit here. return propagation.NewCompositeTextMapPropagator(), nil } p, ok := propagators.load(name) if !ok { unknown = append(unknown, name) continue } props = append(props, p) } var err error if len(unknown) > 0 { joined := strings.Join(unknown, ",") err = fmt.Errorf("%w: %s", errUnknownPropagator, joined) } switch len(props) { case 0: return nil, err case 1: // Do not return a composite of a single propagator. return props[0], err default: return propagation.NewCompositeTextMapPropagator(props...), err } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/autoprop/registry_test.go000066400000000000000000000044571443314701600313050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package autoprop import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/propagation" ) var noop = propagation.NewCompositeTextMapPropagator() func TestRegistryEmptyStore(t *testing.T) { r := registry{} assert.NotPanics(t, func() { require.NoError(t, r.store("first", noop)) }) } func TestRegistryEmptyLoad(t *testing.T) { r := registry{} assert.NotPanics(t, func() { v, ok := r.load("non-existent") assert.False(t, ok, "empty registry should hold nothing") assert.Nil(t, v, "non-nil propagator returned") }) } func TestRegistryConcurrentSafe(t *testing.T) { const propName = "prop" r := registry{} assert.NotPanics(t, func() { require.NoError(t, r.store(propName, noop)) }) go func() { assert.NotPanics(t, func() { require.ErrorIs(t, r.store(propName, noop), errDupReg) }) }() go func() { assert.NotPanics(t, func() { v, ok := r.load(propName) assert.True(t, ok, "missing propagator in registry") assert.Equal(t, noop, v, "wrong propagator retuned") }) }() } func TestRegisterTextMapPropagator(t *testing.T) { const propName = "custom" RegisterTextMapPropagator(propName, noop) t.Cleanup(func() { propagators.drop(propName) }) v, ok := propagators.load(propName) assert.True(t, ok, "missing propagator in envRegistry") assert.Equal(t, noop, v, "wrong propagator stored") } func TestDuplicateRegisterTextMapPropagatorPanics(t *testing.T) { const propName = "custom" RegisterTextMapPropagator(propName, noop) t.Cleanup(func() { propagators.drop(propName) }) errString := fmt.Sprintf("%s: %q", errDupReg, propName) assert.PanicsWithError(t, errString, func() { RegisterTextMapPropagator(propName, noop) }) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/000077500000000000000000000000001443314701600247565ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/go.mod000066400000000000000000000010421443314701600260610ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/aws go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/go.sum000066400000000000000000000042761443314701600261220ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/version.go000066400000000000000000000017731443314701600270020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aws // import "go.opentelemetry.io/contrib/propagators/aws" // Version is the current release version of the AWS XRay propagator. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/000077500000000000000000000000001443314701600257415ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/README.MD000066400000000000000000000006061443314701600271220ustar00rootroot00000000000000# AWS X-Ray Propagator/IDGenerator This package contains an AWS X-Ray compatible `TextMapPropagator` and `IDGenerator`. ## `traceIdRatioSampler` and `x-ray IDGenerator` compatibility It is a general suggestion to **not** use the `traceIDRatioSampler` while also using the X-Ray `IDGenerator`. The non-random nature of building an X-Ray `traceId` may lead to unexpected sampling results. open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/idgenerator.go000066400000000000000000000051021443314701600305710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/propagators/aws/xray" import ( "context" crand "crypto/rand" "encoding/binary" "encoding/hex" "math/rand" "strconv" "sync" "time" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) // IDGenerator is used for generating a new traceID and spanID. type IDGenerator struct { sync.Mutex randSource *rand.Rand } var _ sdktrace.IDGenerator = &IDGenerator{} // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. func (gen *IDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID { gen.Lock() defer gen.Unlock() sid := trace.SpanID{} _, _ = gen.randSource.Read(sid[:]) return sid } // NewIDs returns a non-zero trace ID and a non-zero span ID. // trace ID returned is based on AWS X-Ray TraceID format. // - https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids // // span ID is from a randomly-chosen sequence. func (gen *IDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) { gen.Lock() defer gen.Unlock() tid := trace.TraceID{} currentTime := getCurrentTimeHex() copy(tid[:4], currentTime) _, _ = gen.randSource.Read(tid[4:]) sid := trace.SpanID{} _, _ = gen.randSource.Read(sid[:]) return tid, sid } // NewIDGenerator returns an IDGenerator reference used for sending traces to AWS X-Ray. func NewIDGenerator() *IDGenerator { gen := &IDGenerator{} var rngSeed int64 _ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed) gen.randSource = rand.New(rand.NewSource(rngSeed)) return gen } func getCurrentTimeHex() []uint8 { currentTime := time.Now().Unix() // Ignore error since no expected error should result from this operation // Odd-length strings and non-hex digits are the only 2 error conditions for hex.DecodeString() // strconv.FromatInt() do not produce odd-length strings or non-hex digits currentTimeHex, _ := hex.DecodeString(strconv.FormatInt(currentTime, 16)) return currentTimeHex } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/idgenerator_benchmark_test.go000066400000000000000000000025341443314701600336500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "context" "testing" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) var tracer trace.Tracer func init() { idg := NewIDGenerator() tracer = sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithIDGenerator(idg), ).Tracer("sample-app") } func BenchmarkStartAndEndSampledSpan(b *testing.B) { for i := 0; i < b.N; i++ { _, span := tracer.Start(context.Background(), "Example Trace") span.End() } } func BenchmarkStartAndEndNestedSampledSpan(b *testing.B) { ctx, parent := tracer.Start(context.Background(), "Parent operation...") defer parent.End() b.ResetTimer() for i := 0; i < b.N; i++ { _, span := tracer.Start(ctx, "Sub operation...") span.End() } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/idgenerator_test.go000066400000000000000000000062311443314701600316340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "bytes" "context" "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" ) func TestTraceIDIsValidLength(t *testing.T) { idg := NewIDGenerator() traceID, _ := idg.NewIDs(context.Background()) expectedTraceIDLength := 32 assert.Equal(t, len(traceID.String()), expectedTraceIDLength, "TraceID has incorrect length.") } func TestTraceIDIsUnique(t *testing.T) { idg := NewIDGenerator() traceID1, _ := idg.NewIDs(context.Background()) traceID2, _ := idg.NewIDs(context.Background()) assert.NotEqual(t, traceID1.String(), traceID2.String(), "TraceID should be unique") } func TestTraceIDTimestampInBounds(t *testing.T) { idg := NewIDGenerator() previousTime := time.Now().Unix() traceID, _ := idg.NewIDs(context.Background()) currentTime, err := strconv.ParseInt(traceID.String()[0:8], 16, 64) require.NoError(t, err) nextTime := time.Now().Unix() assert.LessOrEqual(t, previousTime, currentTime, "TraceID is generated incorrectly with the wrong timestamp.") assert.LessOrEqual(t, currentTime, nextTime, "TraceID is generated incorrectly with the wrong timestamp.") } func TestTraceIDIsNotNil(t *testing.T) { var nilTraceID trace.TraceID idg := NewIDGenerator() traceID, _ := idg.NewIDs(context.Background()) assert.False(t, bytes.Equal(traceID[:], nilTraceID[:]), "TraceID cannot be empty.") } func TestSpanIDIsValidLength(t *testing.T) { idg := NewIDGenerator() ctx := context.Background() traceID, spanID1 := idg.NewIDs(ctx) spanID2 := idg.NewSpanID(context.Background(), traceID) expectedSpanIDLength := 16 assert.Equal(t, len(spanID1.String()), expectedSpanIDLength, "SpanID has incorrect length") assert.Equal(t, len(spanID2.String()), expectedSpanIDLength, "SpanID has incorrect length") } func TestSpanIDIsUnique(t *testing.T) { idg := NewIDGenerator() ctx := context.Background() traceID, spanID1 := idg.NewIDs(ctx) _, spanID2 := idg.NewIDs(ctx) spanID3 := idg.NewSpanID(ctx, traceID) spanID4 := idg.NewSpanID(ctx, traceID) assert.NotEqual(t, spanID1.String(), spanID2.String(), "SpanID should be unique") assert.NotEqual(t, spanID3.String(), spanID4.String(), "SpanID should be unique") } func TestSpanIDIsNotNil(t *testing.T) { var nilSpanID trace.SpanID idg := NewIDGenerator() ctx := context.Background() traceID, spanID1 := idg.NewIDs(ctx) spanID2 := idg.NewSpanID(ctx, traceID) assert.False(t, bytes.Equal(spanID1[:], nilSpanID[:]), "SpanID cannot be empty.") assert.False(t, bytes.Equal(spanID2[:], nilSpanID[:]), "SpanID cannot be empty.") } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/propagator.go000066400000000000000000000136601443314701600304540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/propagators/aws/xray" import ( "context" "errors" "strings" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const ( traceHeaderKey = "X-Amzn-Trace-Id" traceHeaderDelimiter = ";" kvDelimiter = "=" traceIDKey = "Root" sampleFlagKey = "Sampled" parentIDKey = "Parent" traceIDVersion = "1" traceIDDelimiter = "-" isSampled = "1" notSampled = "0" traceFlagNone = 0x0 traceFlagSampled = 0x1 << 0 traceIDLength = 35 traceIDDelimitterIndex1 = 1 traceIDDelimitterIndex2 = 10 traceIDFirstPartLength = 8 sampledFlagLength = 1 ) var ( empty = trace.SpanContext{} errInvalidTraceHeader = errors.New("invalid X-Amzn-Trace-Id header value, should contain 3 different part separated by ;") errMalformedTraceID = errors.New("cannot decode trace ID from header") errLengthTraceIDHeader = errors.New("incorrect length of X-Ray trace ID found, 35 character length expected") errInvalidTraceIDVersion = errors.New("invalid X-Ray trace ID header found, does not have valid trace ID version") errInvalidSpanIDLength = errors.New("invalid span ID length, must be 16") ) // Propagator serializes Span Context to/from AWS X-Ray headers. // // Example AWS X-Ray format: // // X-Amzn-Trace-Id: Root={traceId};Parent={parentId};Sampled={samplingFlag}. type Propagator struct{} // Asserts that the propagator implements the otel.TextMapPropagator interface at compile time. var _ propagation.TextMapPropagator = &Propagator{} // Inject injects a context to the carrier following AWS X-Ray format. func (xray Propagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { sc := trace.SpanFromContext(ctx).SpanContext() if !sc.TraceID().IsValid() || !sc.SpanID().IsValid() { return } otTraceID := sc.TraceID().String() xrayTraceID := traceIDVersion + traceIDDelimiter + otTraceID[0:traceIDFirstPartLength] + traceIDDelimiter + otTraceID[traceIDFirstPartLength:] parentID := sc.SpanID() samplingFlag := notSampled if sc.TraceFlags() == traceFlagSampled { samplingFlag = isSampled } headers := []string{traceIDKey, kvDelimiter, xrayTraceID, traceHeaderDelimiter, parentIDKey, kvDelimiter, parentID.String(), traceHeaderDelimiter, sampleFlagKey, kvDelimiter, samplingFlag} carrier.Set(traceHeaderKey, strings.Join(headers, "")) } // Extract gets a context from the carrier if it contains AWS X-Ray headers. func (xray Propagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { // extract tracing information if header := carrier.Get(traceHeaderKey); header != "" { sc, err := extract(header) if err == nil && sc.IsValid() { return trace.ContextWithRemoteSpanContext(ctx, sc) } } return ctx } // extract extracts Span Context from context. func extract(headerVal string) (trace.SpanContext, error) { var ( scc = trace.SpanContextConfig{} err error delimiterIndex int part string ) pos := 0 for pos < len(headerVal) { delimiterIndex = indexOf(headerVal, traceHeaderDelimiter, pos) if delimiterIndex >= 0 { part = headerVal[pos:delimiterIndex] pos = delimiterIndex + 1 } else { //last part part = strings.TrimSpace(headerVal[pos:]) pos = len(headerVal) } equalsIndex := strings.Index(part, kvDelimiter) if equalsIndex < 0 { return empty, errInvalidTraceHeader } value := part[equalsIndex+1:] if strings.HasPrefix(part, traceIDKey) { scc.TraceID, err = parseTraceID(value) if err != nil { return empty, err } } else if strings.HasPrefix(part, parentIDKey) { //extract parentId scc.SpanID, err = trace.SpanIDFromHex(value) if err != nil { return empty, errInvalidSpanIDLength } } else if strings.HasPrefix(part, sampleFlagKey) { //extract traceflag scc.TraceFlags = parseTraceFlag(value) } } return trace.NewSpanContext(scc), nil } // indexOf returns position of the first occurrence of a substr in str starting at pos index. func indexOf(str string, substr string, pos int) int { index := strings.Index(str[pos:], substr) if index > -1 { index += pos } return index } // parseTraceID returns trace ID if valid else return invalid trace ID. func parseTraceID(xrayTraceID string) (trace.TraceID, error) { if len(xrayTraceID) != traceIDLength { return empty.TraceID(), errLengthTraceIDHeader } if !strings.HasPrefix(xrayTraceID, traceIDVersion) { return empty.TraceID(), errInvalidTraceIDVersion } if xrayTraceID[traceIDDelimitterIndex1:traceIDDelimitterIndex1+1] != traceIDDelimiter || xrayTraceID[traceIDDelimitterIndex2:traceIDDelimitterIndex2+1] != traceIDDelimiter { return empty.TraceID(), errMalformedTraceID } epochPart := xrayTraceID[traceIDDelimitterIndex1+1 : traceIDDelimitterIndex2] uniquePart := xrayTraceID[traceIDDelimitterIndex2+1 : traceIDLength] result := epochPart + uniquePart return trace.TraceIDFromHex(result) } // parseTraceFlag returns a parsed trace flag. func parseTraceFlag(xraySampledFlag string) trace.TraceFlags { if len(xraySampledFlag) == sampledFlagLength && xraySampledFlag != isSampled { return traceFlagNone } return trace.FlagsSampled } // Fields returns list of fields used by HTTPTextFormat. func (xray Propagator) Fields() []string { return []string{traceHeaderKey} } open-telemetry-opentelemetry-go-contrib-2135499/propagators/aws/xray/propagator_test.go000066400000000000000000000070241443314701600315100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "context" "net/http" "strings" "testing" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/trace" ) var ( traceID = trace.TraceID{0x8a, 0x3c, 0x60, 0xf7, 0xd1, 0x88, 0xf8, 0xfa, 0x79, 0xd4, 0x8a, 0x39, 0x1a, 0x77, 0x8f, 0xa6} xrayTraceID = "1-8a3c60f7-d188f8fa79d48a391a778fa6" xrayTraceIDIncorrectLength = "1-82138-1203123" parentID64Str = "53995c3f42cd8ad8" parentSpanID = trace.SpanID{0x53, 0x99, 0x5c, 0x3f, 0x42, 0xcd, 0x8a, 0xd8} zeroSpanIDStr = "0000000000000000" wrongVersionTraceHeaderID = "5b00000000b000000000000000000000000" ) func TestAwsXrayExtract(t *testing.T) { testData := []struct { traceID string parentSpanID string samplingFlag string expected trace.SpanContextConfig err error }{ { xrayTraceID, parentID64Str, notSampled, trace.SpanContextConfig{ TraceID: traceID, SpanID: parentSpanID, TraceFlags: traceFlagNone, }, nil, }, { xrayTraceID, parentID64Str, isSampled, trace.SpanContextConfig{ TraceID: traceID, SpanID: parentSpanID, TraceFlags: traceFlagSampled, }, nil, }, { xrayTraceID, zeroSpanIDStr, isSampled, trace.SpanContextConfig{}, errInvalidSpanIDLength, }, { xrayTraceIDIncorrectLength, parentID64Str, isSampled, trace.SpanContextConfig{}, errLengthTraceIDHeader, }, { wrongVersionTraceHeaderID, parentID64Str, isSampled, trace.SpanContextConfig{}, errInvalidTraceIDVersion, }, } for _, test := range testData { headerVal := strings.Join([]string{traceIDKey, kvDelimiter, test.traceID, traceHeaderDelimiter, parentIDKey, kvDelimiter, test.parentSpanID, traceHeaderDelimiter, sampleFlagKey, kvDelimiter, test.samplingFlag}, "") sc, err := extract(headerVal) info := []interface{}{ "trace ID: %q, parent span ID: %q, sampling flag: %q", test.traceID, test.parentSpanID, test.samplingFlag, } if !assert.Equal(t, test.err, err, info...) { continue } assert.Equal(t, trace.NewSpanContext(test.expected), sc, info...) } } func BenchmarkPropagatorExtract(b *testing.B) { propagator := Propagator{} ctx := context.Background() req, _ := http.NewRequest("GET", "http://example.com", nil) req.Header.Set("Root", "1-8a3c60f7-d188f8fa79d48a391a778fa6") req.Header.Set("Parent", "53995c3f42cd8ad8") req.Header.Set("Sampled", "1") b.ResetTimer() for i := 0; i < b.N; i++ { _ = propagator.Extract(ctx, propagation.HeaderCarrier(req.Header)) } } func BenchmarkPropagatorInject(b *testing.B) { propagator := Propagator{} tracer := otel.Tracer("test") req, _ := http.NewRequest("GET", "http://example.com", nil) ctx, _ := tracer.Start(context.Background(), "Parent operation...") b.ResetTimer() for i := 0; i < b.N; i++ { propagator.Inject(ctx, propagation.HeaderCarrier(req.Header)) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/000077500000000000000000000000001443314701600244705ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_benchmark_test.go000066400000000000000000000046471443314701600304070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3_test import ( "context" "net/http" "testing" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func BenchmarkExtractB3(b *testing.B) { testGroup := []struct { name string tests []extractTest }{ { name: "valid headers", tests: extractHeaders, }, { name: "invalid headers", tests: extractInvalidHeaders, }, } for _, tg := range testGroup { propagator := b3.New() for _, tt := range tg.tests { traceBenchmark(tg.name+"/"+tt.name, b, func(b *testing.B) { ctx := context.Background() req, _ := http.NewRequest("GET", "http://example.com", nil) for h, v := range tt.headers { req.Header.Set(h, v) } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = propagator.Extract(ctx, propagation.HeaderCarrier(req.Header)) } }) } } } func BenchmarkInjectB3(b *testing.B) { testGroup := []struct { name string tests []injectTest }{ { name: "valid headers", tests: injectHeader, }, { name: "invalid headers", tests: injectInvalidHeader, }, } for _, tg := range testGroup { for _, tt := range tg.tests { propagator := b3.New(b3.WithInjectEncoding(tt.encoding)) traceBenchmark(tg.name+"/"+tt.name, b, func(b *testing.B) { req, _ := http.NewRequest("GET", "http://example.com", nil) ctx := trace.ContextWithSpan( context.Background(), testSpan{sc: trace.NewSpanContext(tt.scc)}, ) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { propagator.Inject(ctx, propagation.HeaderCarrier(req.Header)) } }) } } } func traceBenchmark(name string, b *testing.B, fn func(*testing.B)) { b.Run(name, func(b *testing.B) { b.ReportAllocs() fn(b) }) b.Run(name, func(b *testing.B) { b.ReportAllocs() fn(b) }) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_config.go000066400000000000000000000046251443314701600266570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 // import "go.opentelemetry.io/contrib/propagators/b3" type config struct { // InjectEncoding are the B3 encodings used when injecting trace // information. If no encoding is specified (i.e. `B3Unspecified`) // `B3SingleHeader` will be used as the default. InjectEncoding Encoding } // Option interface used for setting optional config properties. type Option interface { apply(*config) } type optionFunc func(*config) func (o optionFunc) apply(c *config) { o(c) } // newConfig creates a new config struct and applies opts to it. func newConfig(opts ...Option) *config { c := &config{} for _, opt := range opts { opt.apply(c) } return c } // Encoding is a bitmask representation of the B3 encoding type. type Encoding uint8 // supports returns if e has o bit(s) set. func (e Encoding) supports(o Encoding) bool { return e&o == o } const ( // B3Unspecified is an unspecified B3 encoding. B3Unspecified Encoding = 0 // B3MultipleHeader is a B3 encoding that uses multiple headers to // transmit tracing information all prefixed with `x-b3-`. // x-b3-traceid: {TraceId} // x-b3-parentspanid: {ParentSpanId} // x-b3-spanid: {SpanId} // x-b3-sampled: {SamplingState} // x-b3-flags: {DebugFlag} B3MultipleHeader Encoding = 1 << iota // B3SingleHeader is a B3 encoding that uses a single header named `b3` // to transmit tracing information. // b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} B3SingleHeader ) // WithInjectEncoding sets the encoding the propagator will inject. // The encoding is interpreted as a bitmask. Therefore // // WithInjectEncoding(B3SingleHeader | B3MultipleHeader) // // means the propagator will inject both single and multi B3 headers. func WithInjectEncoding(encoding Encoding) Option { return optionFunc(func(c *config) { c.InjectEncoding = encoding }) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_data_test.go000066400000000000000000000560251443314701600273630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3_test import ( "fmt" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel/trace" ) const ( b3Context = "b3" b3Flags = "x-b3-flags" b3TraceID = "x-b3-traceid" b3SpanID = "x-b3-spanid" b3Sampled = "x-b3-sampled" b3ParentSpanID = "x-b3-parentspanid" ) const ( traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736" spanIDStr = "00f067aa0ba902b7" ) var ( traceID = mustTraceIDFromHex(traceIDStr) spanID = mustSpanIDFromHex(spanIDStr) traceID64bitPadded = mustTraceIDFromHex("0000000000000000a3ce929d0e0e4736") ) func mustTraceIDFromHex(s string) (t trace.TraceID) { var err error t, err = trace.TraceIDFromHex(s) if err != nil { panic(err) } return } func mustSpanIDFromHex(s string) (t trace.SpanID) { var err error t, err = trace.SpanIDFromHex(s) if err != nil { panic(err) } return } type extractTest struct { name string headers map[string]string wantScc trace.SpanContextConfig debug bool deferred bool } var extractHeaders = []extractTest{ { name: "empty", headers: map[string]string{}, wantScc: trace.SpanContextConfig{}, }, { name: "multiple: sampling state defer", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, deferred: true, }, { name: "multiple: sampling state deny", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, }, { name: "multiple: sampling state accept", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "1", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "multiple: sampling state as a boolean: true", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "true", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "multiple: sampling state as a boolean: false", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "false", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, }, { name: "multiple: debug flag set", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Flags: "1", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, debug: true, }, { name: "multiple: debug flag set to not 1 (ignored)", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "1", b3Flags: "2", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { // spec explicitly states "Debug implies an accept decision, so don't // also send the X-B3-Sampled header", make sure sampling is set in this case. name: "multiple: debug flag set and sampling state is deny", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", b3Flags: "1", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, debug: true, }, { name: "multiple: with parent span id", headers: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "1", b3ParentSpanID: "00f067aa0ba90200", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "multiple: with only sampled state header", headers: map[string]string{ b3Sampled: "0", }, wantScc: trace.SpanContextConfig{}, }, { name: "multiple: left-padding 64-bit traceID", headers: map[string]string{ b3TraceID: "a3ce929d0e0e4736", b3SpanID: spanIDStr, }, wantScc: trace.SpanContextConfig{ TraceID: traceID64bitPadded, SpanID: spanID, }, deferred: true, }, { name: "single: sampling state defer", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s", traceIDStr, spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, deferred: true, }, { name: "single: sampling state deny", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-0", traceIDStr, spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, }, { name: "single: sampling state accept", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-1", traceIDStr, spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "single: sampling state debug", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-d", traceIDStr, spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, debug: true, }, { name: "single: with parent span id", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-1-00000000000000cd", traceIDStr, spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "single: with only sampling state deny", headers: map[string]string{ b3Context: "0", }, wantScc: trace.SpanContextConfig{}, }, { name: "single: left-padding 64-bit traceID", headers: map[string]string{ b3Context: fmt.Sprintf("a3ce929d0e0e4736-%s", spanIDStr), }, wantScc: trace.SpanContextConfig{ TraceID: traceID64bitPadded, SpanID: spanID, }, deferred: true, }, { name: "both single and multiple: single priority", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-1", traceIDStr, spanIDStr), b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, // An invalid Single Headers should fallback to multiple. { name: "both single and multiple: invalid single", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-", traceIDStr, spanIDStr), b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, }, // Invalid Mult Header should not be noticed as Single takes precedence. { name: "both single and multiple: invalid multiple", headers: map[string]string{ b3Context: fmt.Sprintf("%s-%s-1", traceIDStr, spanIDStr), b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "invalid", }, wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, } var extractInvalidHeaders = []extractTest{ { name: "multiple: trace ID length > 32", headers: map[string]string{ b3TraceID: "ab00000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: trace ID length >16 and <32", headers: map[string]string{ b3TraceID: "ab0000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: trace ID length <16", headers: map[string]string{ b3TraceID: "ab0000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: wrong span ID length", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "cd0000000000000000", b3Sampled: "1", }, }, { name: "multiple: wrong sampled flag length", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "10", }, }, { name: "multiple: bogus trace ID", headers: map[string]string{ b3TraceID: "qw000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: bogus span ID", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "qw00000000000000", b3Sampled: "1", }, }, { name: "multiple: bogus sampled flag", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "d", }, }, { name: "multiple: upper case trace ID", headers: map[string]string{ b3TraceID: "AB000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: upper case span ID", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "CD00000000000000", b3Sampled: "1", }, }, { name: "multiple: zero trace ID", headers: map[string]string{ b3TraceID: "00000000000000000000000000000000", b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: zero span ID", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3SpanID: "0000000000000000", b3Sampled: "1", }, }, { name: "multiple: missing span ID", headers: map[string]string{ b3TraceID: "ab000000000000000000000000000000", b3Sampled: "1", }, }, { name: "multiple: missing trace ID", headers: map[string]string{ b3SpanID: "cd00000000000000", b3Sampled: "1", }, }, { name: "multiple: sampled header set to 1 but trace ID and span ID are missing", headers: map[string]string{ b3Sampled: "1", }, }, { name: "single: wrong trace ID length", headers: map[string]string{ b3Context: "ab00000000000000000000000000000000-cd00000000000000-1", }, }, { name: "single: wrong span ID length", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd0000000000000000-1", }, }, { name: "single: wrong sampled state length", headers: map[string]string{ b3Context: "00-ab000000000000000000000000000000-cd00000000000000-01", }, }, { name: "single: wrong parent span ID length", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd00000000000000-1-cd0000000000000000", }, }, { name: "single: bogus trace ID", headers: map[string]string{ b3Context: "qw000000000000000000000000000000-cd00000000000000-1", }, }, { name: "single: bogus span ID", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-qw00000000000000-1", }, }, { name: "single: bogus sampled flag", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd00000000000000-q", }, }, { name: "single: bogus parent span ID", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd00000000000000-1-qw00000000000000", }, }, { name: "single: upper case trace ID", headers: map[string]string{ b3Context: "AB000000000000000000000000000000-cd00000000000000-1", }, }, { name: "single: upper case span ID", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-CD00000000000000-1", }, }, { name: "single: upper case parent span ID", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd00000000000000-1-EF00000000000000", }, }, { name: "single: zero trace ID and span ID", headers: map[string]string{ b3Context: "00000000000000000000000000000000-0000000000000000-1", }, }, { name: "single: with sampling set to true", headers: map[string]string{ b3Context: "ab000000000000000000000000000000-cd00000000000000-true", }, }, } type injectTest struct { name string encoding b3.Encoding scc trace.SpanContextConfig wantHeaders map[string]string doNotWantHeaders []string debug bool deferred bool } var injectHeader = []injectTest{ { name: "none: sampled", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-%s", traceIDStr, spanIDStr, "1"), }, doNotWantHeaders: []string{ b3ParentSpanID, b3TraceID, b3SpanID, b3Sampled, b3Flags, b3Context, }, }, { name: "none: not sampled", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-%s", traceIDStr, spanIDStr, "0"), }, doNotWantHeaders: []string{ b3ParentSpanID, b3TraceID, b3SpanID, b3Sampled, b3Flags, b3Context, }, }, { name: "none: unset sampled", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3Sampled, b3TraceID, b3SpanID, b3ParentSpanID, b3Flags, b3Context, }, deferred: true, }, { name: "none: sampled only", scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: "1", }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3ParentSpanID, b3Flags, b3Context, }, }, { name: "none: debug", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-%s", traceIDStr, spanIDStr, "d"), }, doNotWantHeaders: []string{ b3Sampled, traceIDStr, spanIDStr, b3ParentSpanID, b3Context, }, debug: true, }, { name: "none: debug omitting sample", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-%s", traceIDStr, spanIDStr, "d"), }, doNotWantHeaders: []string{ b3Sampled, traceIDStr, spanIDStr, b3Flags, b3ParentSpanID, b3Context, }, debug: true, }, { name: "multiple: sampled", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "1", }, doNotWantHeaders: []string{ b3ParentSpanID, b3Flags, b3Context, }, }, { name: "multiple: not sampled", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", }, doNotWantHeaders: []string{ b3ParentSpanID, b3Flags, b3Context, }, }, { name: "multiple: unset sampled", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, b3Flags, b3Context, }, deferred: true, }, { name: "multiple: sampled only", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Sampled: "1", }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3ParentSpanID, b3Flags, b3Context, }, }, { name: "multiple: debug", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Flags: "1", }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, b3Context, }, debug: true, }, { name: "multiple: debug omitting sample", encoding: b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Flags: "1", }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, b3Context, }, debug: true, }, { name: "single: sampled", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-1", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3Sampled, b3ParentSpanID, b3Flags, }, }, { name: "single: not sampled", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-0", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3Sampled, b3ParentSpanID, b3Flags, }, }, { name: "single: unset sampled", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3Sampled, b3ParentSpanID, b3Flags, }, deferred: true, }, { name: "single: sampled only", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: "1", }, doNotWantHeaders: []string{ b3Sampled, b3TraceID, b3SpanID, b3ParentSpanID, b3Flags, b3Context, }, }, { name: "single: debug", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-d", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3Flags, b3Sampled, b3ParentSpanID, b3Context, }, debug: true, }, { name: "single: debug omitting sample", encoding: b3.B3SingleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: fmt.Sprintf("%s-%s-d", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3Flags, b3Sampled, b3ParentSpanID, b3Context, }, debug: true, }, { name: "single+multiple: sampled", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "1", b3Context: fmt.Sprintf("%s-%s-1", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3ParentSpanID, b3Flags, }, }, { name: "single+multiple: not sampled", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Sampled: "0", b3Context: fmt.Sprintf("%s-%s-0", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3ParentSpanID, b3Flags, }, }, { name: "single+multiple: unset sampled", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Context: fmt.Sprintf("%s-%s", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, b3Flags, }, deferred: true, }, { name: "single+multiple: sampled only", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3Context: "1", b3Sampled: "1", }, doNotWantHeaders: []string{ b3TraceID, b3SpanID, b3ParentSpanID, b3Flags, }, }, { name: "single+multiple: debug", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Flags: "1", b3Context: fmt.Sprintf("%s-%s-d", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, }, debug: true, }, { name: "single+multiple: debug omitting sample", encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ b3TraceID: traceIDStr, b3SpanID: spanIDStr, b3Flags: "1", b3Context: fmt.Sprintf("%s-%s-d", traceIDStr, spanIDStr), }, doNotWantHeaders: []string{ b3Sampled, b3ParentSpanID, }, debug: true, }, } var injectInvalidHeaderGenerator = []injectTest{ { name: "empty", scc: trace.SpanContextConfig{}, }, { name: "missing traceID", scc: trace.SpanContextConfig{ SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "missing spanID", scc: trace.SpanContextConfig{ TraceID: traceID, TraceFlags: trace.FlagsSampled, }, }, { name: "missing traceID and spanID", scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, }, } var injectInvalidHeader []injectTest func init() { // Preform a test for each invalid injectTest with all combinations of // encoding values. injectInvalidHeader = make([]injectTest, 0, len(injectInvalidHeaderGenerator)*4) allHeaders := []string{ b3TraceID, b3SpanID, b3Sampled, b3ParentSpanID, b3Flags, b3Context, } // Nothing should be set for any header regardless of encoding. for _, t := range injectInvalidHeaderGenerator { injectInvalidHeader = append(injectInvalidHeader, injectTest{ name: "none: " + t.name, scc: t.scc, doNotWantHeaders: allHeaders, }) injectInvalidHeader = append(injectInvalidHeader, injectTest{ name: "multiple: " + t.name, encoding: b3.B3MultipleHeader, scc: t.scc, doNotWantHeaders: allHeaders, }) injectInvalidHeader = append(injectInvalidHeader, injectTest{ name: "single: " + t.name, encoding: b3.B3SingleHeader, scc: t.scc, doNotWantHeaders: allHeaders, }) injectInvalidHeader = append(injectInvalidHeader, injectTest{ name: "single+multiple: " + t.name, encoding: b3.B3SingleHeader | b3.B3MultipleHeader, scc: t.scc, doNotWantHeaders: allHeaders, }) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_example_test.go000066400000000000000000000020551443314701600300770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3_test import ( "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" ) func ExampleNew() { p := b3.New() // Register the B3 propagator globally. otel.SetTextMapPropagator(p) } func ExampleNew_injectEncoding() { // Create a B3 propagator configured to inject context with both multiple // and single header B3 HTTP encoding. p := b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader | b3.B3SingleHeader)) otel.SetTextMapPropagator(p) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_integration_test.go000066400000000000000000000104771443314701600307760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3_test import ( "context" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func TestExtractB3(t *testing.T) { testGroup := []struct { name string tests []extractTest }{ { name: "valid extract headers", tests: extractHeaders, }, { name: "invalid extract headers", tests: extractInvalidHeaders, }, } for _, tg := range testGroup { propagator := b3.New() for _, tt := range tg.tests { t.Run(tt.name, func(t *testing.T) { header := make(http.Header, len(tt.headers)) for h, v := range tt.headers { header.Set(h, v) } ctx := context.Background() ctx = propagator.Extract(ctx, propagation.HeaderCarrier(header)) gotSc := trace.SpanContextFromContext(ctx) comparer := cmp.Comparer(func(a, b trace.SpanContext) bool { // Do not compare remote field, it is unset on empty // SpanContext. newA := a.WithRemote(b.IsRemote()) return newA.Equal(b) }) if diff := cmp.Diff(gotSc, trace.NewSpanContext(tt.wantScc), comparer); diff != "" { t.Errorf("%s: %s: -got +want %s", tg.name, tt.name, diff) } assert.Equal(t, tt.debug, b3.DebugFromContext(ctx)) assert.Equal(t, tt.deferred, b3.DeferredFromContext(ctx)) }) } } } type testSpan struct { trace.Span sc trace.SpanContext } func (s testSpan) SpanContext() trace.SpanContext { return s.sc } func TestInjectB3(t *testing.T) { testGroup := []struct { name string tests []injectTest }{ { name: "valid inject headers", tests: injectHeader, }, { name: "invalid inject headers", tests: injectInvalidHeader, }, } for _, tg := range testGroup { for _, tt := range tg.tests { propagator := b3.New(b3.WithInjectEncoding(tt.encoding)) t.Run(tt.name, func(t *testing.T) { header := http.Header{} ctx := trace.ContextWithSpanContext( context.Background(), trace.NewSpanContext(tt.scc), ) ctx = b3.WithDebug(ctx, tt.debug) ctx = b3.WithDeferred(ctx, tt.deferred) propagator.Inject(ctx, propagation.HeaderCarrier(header)) for h, v := range tt.wantHeaders { got, want := header.Get(h), v if diff := cmp.Diff(got, want); diff != "" { t.Errorf("%s: %s, header=%s: -got +want %s", tg.name, tt.name, h, diff) } } for _, h := range tt.doNotWantHeaders { v, gotOk := header[h] if diff := cmp.Diff(gotOk, false); diff != "" { t.Errorf("%s: %s, header=%s: -got +want %s, value=%s", tg.name, tt.name, h, diff, v) } } }) } } } func TestB3Propagator_Fields(t *testing.T) { tests := []struct { name string propagator propagation.TextMapPropagator want []string }{ { name: "no encoding specified", propagator: b3.New(), want: []string{ b3TraceID, b3SpanID, b3Sampled, b3Flags, }, }, { name: "B3MultipleHeader encoding specified", propagator: b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader)), want: []string{ b3TraceID, b3SpanID, b3Sampled, b3Flags, }, }, { name: "B3SingleHeader encoding specified", propagator: b3.New(b3.WithInjectEncoding(b3.B3SingleHeader)), want: []string{ b3Context, }, }, { name: "B3SingleHeader and B3MultipleHeader encoding specified", propagator: b3.New(b3.WithInjectEncoding(b3.B3SingleHeader | b3.B3MultipleHeader)), want: []string{ b3Context, b3TraceID, b3SpanID, b3Sampled, b3Flags, }, }, } for _, test := range tests { if diff := cmp.Diff(test.propagator.Fields(), test.want); diff != "" { t.Errorf("%s: Fields: -got +want %s", test.name, diff) } } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_propagator.go000066400000000000000000000260241443314701600275650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 // import "go.opentelemetry.io/contrib/propagators/b3" import ( "context" "errors" "strings" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const ( // Default B3 Header names. b3ContextHeader = "b3" b3DebugFlagHeader = "x-b3-flags" b3TraceIDHeader = "x-b3-traceid" b3SpanIDHeader = "x-b3-spanid" b3SampledHeader = "x-b3-sampled" b3ParentSpanIDHeader = "x-b3-parentspanid" b3TraceIDPadding = "0000000000000000" // B3 Single Header encoding widths. separatorWidth = 1 // Single "-" character. samplingWidth = 1 // Single hex character. traceID64BitsWidth = 64 / 4 // 16 hex character Trace ID. traceID128BitsWidth = 128 / 4 // 32 hex character Trace ID. spanIDWidth = 16 // 16 hex character ID. parentSpanIDWidth = 16 // 16 hex character ID. ) var ( empty = trace.SpanContext{} errInvalidSampledByte = errors.New("invalid B3 Sampled found") errInvalidSampledHeader = errors.New("invalid B3 Sampled header found") errInvalidTraceIDHeader = errors.New("invalid B3 traceID header found") errInvalidSpanIDHeader = errors.New("invalid B3 spanID header found") errInvalidParentSpanIDHeader = errors.New("invalid B3 ParentSpanID header found") errInvalidScope = errors.New("require either both traceID and spanID or none") errInvalidScopeParent = errors.New("traceID and spanID required for ParentSpanID") errInvalidScopeParentSingle = errors.New("traceID, spanID and Sampled required for ParentSpanID") errEmptyContext = errors.New("empty request context") errInvalidTraceIDValue = errors.New("invalid B3 traceID value found") errInvalidSpanIDValue = errors.New("invalid B3 spanID value found") errInvalidParentSpanIDValue = errors.New("invalid B3 ParentSpanID value found") ) type propagator struct { cfg config } var _ propagation.TextMapPropagator = propagator{} // New creates a B3 implementation of propagation.TextMapPropagator. // B3 propagator serializes SpanContext to/from B3 Headers. // This propagator supports both versions of B3 headers, // 1. Single Header: // b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} // 2. Multiple Headers: // x-b3-traceid: {TraceId} // x-b3-parentspanid: {ParentSpanId} // x-b3-spanid: {SpanId} // x-b3-sampled: {SamplingState} // x-b3-flags: {DebugFlag} // // The Single Header propagator is used by default. func New(opts ...Option) propagation.TextMapPropagator { cfg := newConfig(opts...) return propagator{ cfg: *cfg, } } // Inject injects a context into the carrier as B3 headers. // The parent span ID is omitted because it is not tracked in the // SpanContext. func (b3 propagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { sc := trace.SpanFromContext(ctx).SpanContext() if b3.cfg.InjectEncoding.supports(B3SingleHeader) || b3.cfg.InjectEncoding == B3Unspecified { header := []string{} if sc.TraceID().IsValid() && sc.SpanID().IsValid() { header = append(header, sc.TraceID().String(), sc.SpanID().String()) } if debugFromContext(ctx) { header = append(header, "d") } else if !(deferredFromContext(ctx)) { if sc.IsSampled() { header = append(header, "1") } else { header = append(header, "0") } } carrier.Set(b3ContextHeader, strings.Join(header, "-")) } if b3.cfg.InjectEncoding.supports(B3MultipleHeader) { if sc.TraceID().IsValid() && sc.SpanID().IsValid() { carrier.Set(b3TraceIDHeader, sc.TraceID().String()) carrier.Set(b3SpanIDHeader, sc.SpanID().String()) } if debugFromContext(ctx) { // Since Debug implies deferred, don't also send "X-B3-Sampled". carrier.Set(b3DebugFlagHeader, "1") } else if !(deferredFromContext(ctx)) { if sc.IsSampled() { carrier.Set(b3SampledHeader, "1") } else { carrier.Set(b3SampledHeader, "0") } } } } // Extract extracts a context from the carrier if it contains B3 headers. func (b3 propagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { var ( sc trace.SpanContext err error ) // Default to Single Header if a valid value exists. if h := carrier.Get(b3ContextHeader); h != "" { ctx, sc, err = extractSingle(ctx, h) if err == nil && sc.IsValid() { return trace.ContextWithRemoteSpanContext(ctx, sc) } // The Single Header value was invalid, fallback to Multiple Header. } var ( traceID = carrier.Get(b3TraceIDHeader) spanID = carrier.Get(b3SpanIDHeader) parentSpanID = carrier.Get(b3ParentSpanIDHeader) sampled = carrier.Get(b3SampledHeader) debugFlag = carrier.Get(b3DebugFlagHeader) ) ctx, sc, err = extractMultiple(ctx, traceID, spanID, parentSpanID, sampled, debugFlag) if err != nil || !sc.IsValid() { // clear the deferred flag if we don't have a valid SpanContext return withDeferred(ctx, false) } return trace.ContextWithRemoteSpanContext(ctx, sc) } func (b3 propagator) Fields() []string { header := []string{} if b3.cfg.InjectEncoding.supports(B3SingleHeader) { header = append(header, b3ContextHeader) } if b3.cfg.InjectEncoding.supports(B3MultipleHeader) || b3.cfg.InjectEncoding == B3Unspecified { header = append(header, b3TraceIDHeader, b3SpanIDHeader, b3SampledHeader, b3DebugFlagHeader) } return header } // extractMultiple reconstructs a SpanContext from header values based on B3 // Multiple header. It is based on the implementation found here: // https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go // and adapted to support a SpanContext. func extractMultiple(ctx context.Context, traceID, spanID, parentSpanID, sampled, flags string) (context.Context, trace.SpanContext, error) { var ( err error requiredCount int scc = trace.SpanContextConfig{} ) // correct values for an existing sampled header are "0" and "1". // For legacy support and being lenient to other tracing implementations we // allow "true" and "false" as inputs for interop purposes. switch strings.ToLower(sampled) { case "0", "false": // Zero value for TraceFlags sample bit is unset. case "1", "true": scc.TraceFlags = trace.FlagsSampled case "": ctx = withDeferred(ctx, true) default: return ctx, empty, errInvalidSampledHeader } // The only accepted value for Flags is "1". This will set Debug bitmask and // sampled bitmask to 1 since debug implicitly means sampled. All other // values and omission of header will be ignored. According to the spec. User // shouldn't send X-B3-Sampled header along with X-B3-Flags header. Thus we will // ignore X-B3-Sampled header when X-B3-Flags header is sent and valid. if flags == "1" { ctx = withDeferred(ctx, false) ctx = withDebug(ctx, true) scc.TraceFlags |= trace.FlagsSampled } if traceID != "" { requiredCount++ id := traceID if len(traceID) == 16 { // Pad 64-bit trace IDs. id = b3TraceIDPadding + traceID } if scc.TraceID, err = trace.TraceIDFromHex(id); err != nil { return ctx, empty, errInvalidTraceIDHeader } } if spanID != "" { requiredCount++ if scc.SpanID, err = trace.SpanIDFromHex(spanID); err != nil { return ctx, empty, errInvalidSpanIDHeader } } if requiredCount != 0 && requiredCount != 2 { return ctx, empty, errInvalidScope } if parentSpanID != "" { if requiredCount == 0 { return ctx, empty, errInvalidScopeParent } // Validate parent span ID but we do not use it so do not save it. if _, err = trace.SpanIDFromHex(parentSpanID); err != nil { return ctx, empty, errInvalidParentSpanIDHeader } } return ctx, trace.NewSpanContext(scc), nil } // extractSingle reconstructs a SpanContext from contextHeader based on a B3 // Single header. It is based on the implementation found here: // https://github.com/openzipkin/zipkin-go/blob/v0.2.2/propagation/b3/spancontext.go // and adapted to support a SpanContext. func extractSingle(ctx context.Context, contextHeader string) (context.Context, trace.SpanContext, error) { if contextHeader == "" { return ctx, empty, errEmptyContext } var ( scc = trace.SpanContextConfig{} sampling string ) headerLen := len(contextHeader) switch { case headerLen == samplingWidth: sampling = contextHeader case headerLen == traceID64BitsWidth || headerLen == traceID128BitsWidth: // Trace ID by itself is invalid. return ctx, empty, errInvalidScope case headerLen >= traceID64BitsWidth+spanIDWidth+separatorWidth: pos := 0 var traceID string switch { case string(contextHeader[traceID64BitsWidth]) == "-": // traceID must be 64 bits pos += traceID64BitsWidth // {traceID} traceID = b3TraceIDPadding + string(contextHeader[0:pos]) case string(contextHeader[32]) == "-": // traceID must be 128 bits pos += traceID128BitsWidth // {traceID} traceID = string(contextHeader[0:pos]) default: return ctx, empty, errInvalidTraceIDValue } var err error scc.TraceID, err = trace.TraceIDFromHex(traceID) if err != nil { return ctx, empty, errInvalidTraceIDValue } pos += separatorWidth // {traceID}- scc.SpanID, err = trace.SpanIDFromHex(contextHeader[pos : pos+spanIDWidth]) if err != nil { return ctx, empty, errInvalidSpanIDValue } pos += spanIDWidth // {traceID}-{spanID} if headerLen > pos { if headerLen == pos+separatorWidth { // {traceID}-{spanID}- is invalid. return ctx, empty, errInvalidSampledByte } pos += separatorWidth // {traceID}-{spanID}- switch { case headerLen == pos+samplingWidth: sampling = string(contextHeader[pos]) case headerLen == pos+parentSpanIDWidth: // {traceID}-{spanID}-{parentSpanID} is invalid. return ctx, empty, errInvalidScopeParentSingle case headerLen == pos+samplingWidth+separatorWidth+parentSpanIDWidth: sampling = string(contextHeader[pos]) pos += samplingWidth + separatorWidth // {traceID}-{spanID}-{sampling}- // Validate parent span ID but we do not use it so do not // save it. _, err = trace.SpanIDFromHex(contextHeader[pos:]) if err != nil { return ctx, empty, errInvalidParentSpanIDValue } default: return ctx, empty, errInvalidParentSpanIDValue } } default: return ctx, empty, errInvalidTraceIDValue } switch sampling { case "": ctx = withDeferred(ctx, true) case "d": ctx = withDebug(ctx, true) scc.TraceFlags = trace.FlagsSampled case "1": scc.TraceFlags = trace.FlagsSampled case "0": // Zero value for TraceFlags sample bit is unset. default: return ctx, empty, errInvalidSampledByte } return ctx, trace.NewSpanContext(scc), nil } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/b3_propagator_test.go000066400000000000000000000224241443314701600306240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 import ( "context" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/trace" ) var ( traceID = trace.TraceID{0, 0, 0, 0, 0, 0, 0, 0x7b, 0, 0, 0, 0, 0, 0, 0x1, 0xc8} traceIDStr = "000000000000007b00000000000001c8" spanID = trace.SpanID{0, 0, 0, 0, 0, 0, 0, 0x7b} spanIDStr = "000000000000007b" ) func TestExtractMultiple(t *testing.T) { tests := []struct { traceID string spanID string parentSpanID string sampled string flags string expected trace.SpanContextConfig err error debug bool deferred bool }{ { "", "", "", "0", "", trace.SpanContextConfig{}, nil, false, false, }, { "", "", "", "", "", trace.SpanContextConfig{}, nil, false, true, }, { "", "", "", "1", "", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, false, false, }, { "", "", "", "", "1", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, true, false, }, { "", "", "", "0", "1", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, true, false, }, { "", "", "", "1", "1", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, true, false, }, { traceIDStr, spanIDStr, "", "", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID}, nil, false, true, }, { traceIDStr, spanIDStr, "", "0", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID}, nil, false, false, }, // Ensure backwards compatibility. { traceIDStr, spanIDStr, "", "false", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID}, nil, false, false, }, { traceIDStr, spanIDStr, "", "1", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, false, false, }, // Ensure backwards compatibility. { traceIDStr, spanIDStr, "", "true", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, false, false, }, { traceIDStr, spanIDStr, "", "a", "", trace.SpanContextConfig{}, errInvalidSampledHeader, false, false, }, { traceIDStr, spanIDStr, "", "1", "1", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, true, false, }, // Invalid flags are discarded. { traceIDStr, spanIDStr, "", "1", "invalid", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, false, false, }, // Support short trace IDs. { "00000000000001c8", spanIDStr, "", "0", "", trace.SpanContextConfig{ TraceID: trace.TraceID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0xc8}, SpanID: spanID, }, nil, false, false, }, { "00000000000001c", spanIDStr, "", "0", "", trace.SpanContextConfig{}, errInvalidTraceIDHeader, false, false, }, { "00000000000001c80", spanIDStr, "", "0", "", trace.SpanContextConfig{}, errInvalidTraceIDHeader, false, false, }, { traceIDStr[:len(traceIDStr)-2], spanIDStr, "", "0", "", trace.SpanContextConfig{}, errInvalidTraceIDHeader, false, false, }, { traceIDStr + "0", spanIDStr, "", "0", "", trace.SpanContextConfig{}, errInvalidTraceIDHeader, false, false, }, { traceIDStr, "00000000000001c", "", "0", "", trace.SpanContextConfig{}, errInvalidSpanIDHeader, false, false, }, { traceIDStr, "00000000000001c80", "", "0", "", trace.SpanContextConfig{}, errInvalidSpanIDHeader, false, false, }, { traceIDStr, "", "", "0", "", trace.SpanContextConfig{}, errInvalidScope, false, false, }, { "", spanIDStr, "", "0", "", trace.SpanContextConfig{}, errInvalidScope, false, false, }, { "", "", spanIDStr, "0", "", trace.SpanContextConfig{}, errInvalidScopeParent, false, false, }, { traceIDStr, spanIDStr, "00000000000001c8", "0", "", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID}, nil, false, false, }, { traceIDStr, spanIDStr, "00000000000001c", "0", "", trace.SpanContextConfig{}, errInvalidParentSpanIDHeader, false, false, }, { traceIDStr, spanIDStr, "00000000000001c80", "0", "", trace.SpanContextConfig{}, errInvalidParentSpanIDHeader, false, false, }, } for _, test := range tests { ctx, actual, err := extractMultiple( context.Background(), test.traceID, test.spanID, test.parentSpanID, test.sampled, test.flags, ) info := []interface{}{ "trace ID: %q, span ID: %q, parent span ID: %q, sampled: %q, flags: %q", test.traceID, test.spanID, test.parentSpanID, test.sampled, test.flags, } if !assert.Equal(t, test.err, err, info...) { continue } assert.Equal(t, trace.NewSpanContext(test.expected), actual, info...) assert.Equal(t, debugFromContext(ctx), test.debug, info...) assert.Equal(t, deferredFromContext(ctx), test.deferred, info...) } } func TestExtractSingle(t *testing.T) { tests := []struct { header string expected trace.SpanContextConfig err error debug bool deferred bool }{ {"0", trace.SpanContextConfig{}, nil, false, false}, {"1", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, false, false}, {"d", trace.SpanContextConfig{TraceFlags: trace.FlagsSampled}, nil, true, false}, {"a", trace.SpanContextConfig{}, errInvalidSampledByte, false, false}, {"3", trace.SpanContextConfig{}, errInvalidSampledByte, false, false}, {"000000000000007b", trace.SpanContextConfig{}, errInvalidScope, false, false}, {"000000000000007b00000000000001c8", trace.SpanContextConfig{}, errInvalidScope, false, false}, // Support short trace IDs. { "00000000000001c8-000000000000007b", trace.SpanContextConfig{ TraceID: trace.TraceID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0xc8}, SpanID: spanID, }, nil, false, true, }, { "000000000000007b00000000000001c8-000000000000007b", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, nil, false, true, }, { "000000000000007b00000000000001c8-000000000000007b-", trace.SpanContextConfig{}, errInvalidSampledByte, false, false, }, { "000000000000007b00000000000001c8-000000000000007b-3", trace.SpanContextConfig{}, errInvalidSampledByte, false, false, }, { "000000000000007b00000000000001c8-000000000000007b-00000000000001c8", trace.SpanContextConfig{}, errInvalidScopeParentSingle, false, false, }, { "000000000000007b00000000000001c8-000000000000007b-1", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, false, false, }, // ParentSpanID is discarded, but should still result in a parsable header. { "000000000000007b00000000000001c8-000000000000007b-1-00000000000001c8", trace.SpanContextConfig{TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled}, nil, false, false, }, { "000000000000007b00000000000001c8-000000000000007b-1-00000000000001c", trace.SpanContextConfig{}, errInvalidParentSpanIDValue, false, false, }, {"", trace.SpanContextConfig{}, errEmptyContext, false, false}, } for _, test := range tests { ctx, actual, err := extractSingle(context.Background(), test.header) if !assert.Equal(t, test.err, err, "header: %s", test.header) { continue } assert.Equal(t, trace.NewSpanContext(test.expected), actual, "header: %s", test.header) assert.Equal(t, debugFromContext(ctx), test.debug) assert.Equal(t, deferredFromContext(ctx), test.deferred) } } func TestB3EncodingOperations(t *testing.T) { encodings := []Encoding{ B3MultipleHeader, B3SingleHeader, B3Unspecified, } // Test for overflow (or something really unexpected). for i, e := range encodings { for j := i + 1; j < i+len(encodings); j++ { o := encodings[j%len(encodings)] assert.False(t, e == o, "%v == %v", e, o) } } // B3Unspecified is a special case, it supports only itself, but is // supported by everything. assert.True(t, B3Unspecified.supports(B3Unspecified)) for _, e := range encodings[:len(encodings)-1] { assert.False(t, B3Unspecified.supports(e), e) assert.True(t, e.supports(B3Unspecified), e) } // Skip the special case for B3Unspecified. for i, e := range encodings[:len(encodings)-1] { // Everything should support itself. assert.True(t, e.supports(e)) for j := i + 1; j < i+len(encodings); j++ { o := encodings[j%len(encodings)] // Any "or" combination should be supportive of an operand. assert.True(t, (e | o).supports(e), "(%[0]v|%[1]v).supports(%[0]v)", e, o) // Bitmasks should be unique. assert.False(t, o.supports(e), "%v.supports(%v)", o, e) } } // Encoding.supports should be more inclusive than equality. all := ^B3Unspecified for _, e := range encodings { assert.True(t, all.supports(e)) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/context.go000066400000000000000000000033611443314701600265060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 // import "go.opentelemetry.io/contrib/propagators/b3" import "context" type b3KeyType int const ( debugKey b3KeyType = iota deferredKey ) // withDebug returns a copy of parent with debug set as the debug flag value . func withDebug(parent context.Context, debug bool) context.Context { return context.WithValue(parent, debugKey, debug) } // debugFromContext returns the debug value stored in ctx. // // If no debug value is stored in ctx false is returned. func debugFromContext(ctx context.Context) bool { if ctx == nil { return false } if debug, ok := ctx.Value(debugKey).(bool); ok { return debug } return false } // withDeferred returns a copy of parent with deferred set as the deferred flag value . func withDeferred(parent context.Context, deferred bool) context.Context { return context.WithValue(parent, deferredKey, deferred) } // deferredFromContext returns the deferred value stored in ctx. // // If no deferred value is stored in ctx false is returned. func deferredFromContext(ctx context.Context) bool { if ctx == nil { return false } if deferred, ok := ctx.Value(deferredKey).(bool); ok { return deferred } return false } open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/context_test.go000066400000000000000000000013751443314701600275500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 var ( WithDebug = withDebug DebugFromContext = debugFromContext WithDeferred = withDeferred DeferredFromContext = deferredFromContext ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/doc.go000066400000000000000000000014171443314701600255670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package b3 implements the B3 propagator specification as defined at // https://github.com/openzipkin/b3-propagation package b3 // import "go.opentelemetry.io/contrib/propagators/b3" open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/go.mod000066400000000000000000000007671443314701600256100ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/b3 go 1.19 require ( github.com/google/go-cmp v0.5.9 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/go.sum000066400000000000000000000037151443314701600256310ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/propagators/b3/version.go000066400000000000000000000017631443314701600265130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b3 // import "go.opentelemetry.io/contrib/propagators/b3" // Version is the current release version of the B3 propagator. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/000077500000000000000000000000001443314701600254215ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/context.go000066400000000000000000000023371443314701600274410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger // import "go.opentelemetry.io/contrib/propagators/jaeger" import "context" type jaegerKeyType int const ( debugKey jaegerKeyType = iota ) // withDebug returns a copy of parent with debug set as the debug flag value . func withDebug(parent context.Context, debug bool) context.Context { return context.WithValue(parent, debugKey, debug) } // debugFromContext returns the debug value stored in ctx. // // If no debug value is stored in ctx false is returned. func debugFromContext(ctx context.Context) bool { if ctx == nil { return false } if debug, ok := ctx.Value(debugKey).(bool); ok { return debug } return false } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/context_test.go000066400000000000000000000012611443314701600304730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger var ( WithDebug = withDebug DebugFromContext = debugFromContext ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/doc.go000066400000000000000000000014761443314701600265250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package jaeger implements the Jaeger propagator specification as defined at // https://www.jaegertracing.io/docs/1.18/client-libraries/#propagation-format package jaeger // import "go.opentelemetry.io/contrib/propagators/jaeger" open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/go.mod000066400000000000000000000007731443314701600265360ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/jaeger go 1.19 require ( github.com/google/go-cmp v0.5.9 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/go.sum000066400000000000000000000037151443314701600265620ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/jaeger_data_test.go000066400000000000000000000150231443314701600312360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger_test import ( "fmt" "go.opentelemetry.io/otel/trace" ) const ( traceID15Str = "3ce929d0e0e4736" traceID16Str = "a3ce929d0e0e4736" traceID32Str = "a1ce929d0e0e4736a3ce929d0e0e4736" spanIDStr = "00f067aa0ba902b7" jaegerHeader = "uber-trace-id" ) var ( traceID15 = trace.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} traceID16 = trace.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} traceID32 = trace.TraceID{0xa1, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} spanID = trace.SpanID{0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7} ) type extractTest struct { name string headers map[string]string expected trace.SpanContextConfig debug bool } var extractHeaders = []extractTest{ { "empty", map[string]string{}, trace.SpanContextConfig{}, false, }, { "sampling state not sample", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:0", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, false, }, { "sampling state sampled", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, { "sampling state debug", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:3", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, true, }, { "sampling state debug but sampled bit didn't set, result in not sampled decision", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:2", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, false, }, { "flag can be various length", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:00001", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, { "flag can be hex numbers", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:ff", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, true, }, { "left padding 60 bit trace ID", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID15Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID15, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, { "left padding 64 bit trace ID", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID16Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID16, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, { "128 bit trace ID", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, { "ignore parent span id", map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:whatever:1", traceID32Str, spanIDStr), }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, false, }, } var invalidExtractHeaders = []extractTest{ { name: "trace ID length > 32", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str+"0000", spanIDStr), }, }, { name: "span ID length is not 16 or 32", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str, spanIDStr+"0000"), }, }, { name: "invalid trace ID", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", "zcd00v0000000000a3ce929d0e0e4736", spanIDStr), }, }, { name: "invalid span ID", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str, "00f0wiredba902b7"), }, }, { name: "invalid flags", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:wired", traceID32Str, spanIDStr), }, }, { name: "invalid separator", headers: map[string]string{ jaegerHeader: fmt.Sprintf("%s-%s-0-1", traceID32Str, spanIDStr), }, }, { name: "missing jaeger header", headers: map[string]string{ jaegerHeader + "not": fmt.Sprintf("%s:%s:0:1", traceID32Str, spanIDStr), }, }, { name: "empty header value", headers: map[string]string{ jaegerHeader: "", }, }, } type injectTest struct { name string scc trace.SpanContextConfig wantHeaders map[string]string debug bool } var injectHeaders = []injectTest{ { name: "sampled", scc: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:1", traceID32Str, spanIDStr), }, }, { name: "debug", scc: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:3", traceID32Str, spanIDStr), }, debug: true, }, { name: "not sampled", scc: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, wantHeaders: map[string]string{ jaegerHeader: fmt.Sprintf("%s:%s:0:0", traceID32Str, spanIDStr), }, }, } var invalidInjectHeaders = []injectTest{ { name: "empty", scc: trace.SpanContextConfig{}, }, { name: "missing traceID", scc: trace.SpanContextConfig{ SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "missing spanID", scc: trace.SpanContextConfig{ TraceID: traceID32, TraceFlags: trace.FlagsSampled, }, }, { name: "missing both traceID and spanID", scc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, }, } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/jaeger_example_test.go000066400000000000000000000014611443314701600317610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger_test import ( "go.opentelemetry.io/contrib/propagators/jaeger" "go.opentelemetry.io/otel" ) func ExampleJaeger() { p := jaeger.Jaeger{} // register jaeger propagator otel.SetTextMapPropagator(p) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/jaeger_integration_test.go000066400000000000000000000054471443314701600326610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger_test import ( "context" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/contrib/propagators/jaeger" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func TestExtractJaeger(t *testing.T) { testGroup := []struct { name string testcases []extractTest }{ { name: "valid test case", testcases: extractHeaders, }, { name: "invalid test case", testcases: invalidExtractHeaders, }, } for _, tg := range testGroup { propagator := jaeger.Jaeger{} for _, tc := range tg.testcases { t.Run(tc.name, func(t *testing.T) { header := make(http.Header, len(tc.headers)) for k, v := range tc.headers { header.Set(k, v) } ctx := context.Background() ctx = propagator.Extract(ctx, propagation.HeaderCarrier(header)) resSc := trace.SpanContextFromContext(ctx) comparer := cmp.Comparer(func(a, b trace.SpanContext) bool { // Do not compare remote field, it is unset on empty // SpanContext. newA := a.WithRemote(b.IsRemote()) return newA.Equal(b) }) if diff := cmp.Diff(resSc, trace.NewSpanContext(tc.expected), comparer); diff != "" { t.Errorf("%s: %s: -got +want %s", tg.name, tc.name, diff) } assert.Equal(t, tc.debug, jaeger.DebugFromContext(ctx)) }) } } } func TestInjectJaeger(t *testing.T) { testGroup := []struct { name string testcases []injectTest }{ { name: "valid test case", testcases: injectHeaders, }, { name: "invalid test case", testcases: invalidInjectHeaders, }, } for _, tg := range testGroup { for _, tc := range tg.testcases { propagator := jaeger.Jaeger{} t.Run(tc.name, func(t *testing.T) { header := http.Header{} ctx := trace.ContextWithSpanContext( jaeger.WithDebug(context.Background(), tc.debug), trace.NewSpanContext(tc.scc), ) propagator.Inject(ctx, propagation.HeaderCarrier(header)) for h, v := range tc.wantHeaders { result, want := header.Get(h), v if diff := cmp.Diff(result, want); diff != "" { t.Errorf("%s: %s, header=%s: -got +want %s", tg.name, tc.name, h, diff) } } }) } } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/jaeger_propagator.go000066400000000000000000000120121443314701600314370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger // import "go.opentelemetry.io/contrib/propagators/jaeger" import ( "context" "errors" "fmt" "strconv" "strings" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const ( jaegerHeader = "uber-trace-id" separator = ":" traceID128bitsWidth = 128 / 4 spanIDWidth = 64 / 4 idPaddingChar = "0" flagsDebug = 0x02 flagsSampled = 0x01 flagsNotSampled = 0x00 deprecatedParentSpanID = "0" ) var ( empty = trace.SpanContext{} errMalformedTraceContextVal = errors.New("header value of uber-trace-id should contain four different part separated by : ") errInvalidTraceIDLength = errors.New("invalid trace id length, must be either 16 or 32") errMalformedTraceID = errors.New("cannot decode trace id from header, should be a string of hex, lowercase trace id can't be all zero") errInvalidSpanIDLength = errors.New("invalid span id length, must be 16") errMalformedSpanID = errors.New("cannot decode span id from header, should be a string of hex, lowercase span id can't be all zero") errMalformedFlag = errors.New("cannot decode flag") ) // Jaeger propagator serializes SpanContext to/from Jaeger Headers // // Jaeger format: // // uber-trace-id: {trace-id}:{span-id}:{parent-span-id}:{flags}. type Jaeger struct{} var _ propagation.TextMapPropagator = &Jaeger{} // Inject injects a context to the carrier following jaeger format. // The parent span ID is set to an dummy parent span id as the most implementations do. func (jaeger Jaeger) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { sc := trace.SpanFromContext(ctx).SpanContext() headers := []string{} if !sc.TraceID().IsValid() || !sc.SpanID().IsValid() { return } headers = append(headers, sc.TraceID().String(), sc.SpanID().String(), deprecatedParentSpanID) if debugFromContext(ctx) { headers = append(headers, fmt.Sprintf("%x", flagsDebug|flagsSampled)) } else if sc.IsSampled() { headers = append(headers, fmt.Sprintf("%x", flagsSampled)) } else { headers = append(headers, fmt.Sprintf("%x", flagsNotSampled)) } carrier.Set(jaegerHeader, strings.Join(headers, separator)) } // Extract extracts a context from the carrier if it contains Jaeger headers. func (jaeger Jaeger) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { // extract tracing information if h := carrier.Get(jaegerHeader); h != "" { ctx, sc, err := extract(ctx, h) if err == nil && sc.IsValid() { return trace.ContextWithRemoteSpanContext(ctx, sc) } } return ctx } func extract(ctx context.Context, headerVal string) (context.Context, trace.SpanContext, error) { var ( scc = trace.SpanContextConfig{} err error ) parts := strings.Split(headerVal, separator) if len(parts) != 4 { return ctx, empty, errMalformedTraceContextVal } // extract trace ID if parts[0] != "" { id := parts[0] if len(id) > traceID128bitsWidth { return ctx, empty, errInvalidTraceIDLength } // padding when length is less than 32 if len(id) < traceID128bitsWidth { padCharCount := traceID128bitsWidth - len(id) id = strings.Repeat(idPaddingChar, padCharCount) + id } scc.TraceID, err = trace.TraceIDFromHex(id) if err != nil { return ctx, empty, errMalformedTraceID } } // extract span ID if parts[1] != "" { id := parts[1] if len(id) > spanIDWidth { return ctx, empty, errInvalidSpanIDLength } // padding when length is less than 16 if len(id) < spanIDWidth { padCharCount := spanIDWidth - len(id) id = strings.Repeat(idPaddingChar, padCharCount) + id } scc.SpanID, err = trace.SpanIDFromHex(id) if err != nil { return ctx, empty, errMalformedSpanID } } // skip third part as it is deprecated // extract flag if parts[3] != "" { flagStr := parts[3] flag, err := strconv.ParseInt(flagStr, 16, 64) if err != nil { return ctx, empty, errMalformedFlag } if flag&flagsSampled == flagsSampled { // if sample bit is set, we check if debug bit is also set if flag&flagsDebug == flagsDebug { scc.TraceFlags |= trace.FlagsSampled ctx = withDebug(ctx, true) } else { scc.TraceFlags |= trace.FlagsSampled } } // ignore other bit, including firehose since we don't have corresponding flag in trace context. } return ctx, trace.NewSpanContext(scc), nil } // Fields returns the Jaeger header key whose value is set with Inject. func (jaeger Jaeger) Fields() []string { return []string{jaegerHeader} } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/jaeger_propagator_test.go000066400000000000000000000112261443314701600325040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger import ( "context" "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/trace" ) var ( traceID = trace.TraceID{0, 0, 0, 0, 0, 0, 0, 0, 0xb, 0, 0, 0, 0, 0, 0x1, 0xc8} traceID128Str = "00000000000000000b000000000001c8" zeroTraceIDStr = "00000000000000000000000000000000" traceID64Str = "0b000000000001c8" traceID60Str = "b000000000001c8" spanID = trace.SpanID{0, 0, 0, 0, 0, 0, 0, 0x7b} zeroSpanIDStr = "0000000000000000" spanID64Str = "000000000000007b" spanID60Str = "00000000000007b" ) func TestJaeger_Extract(t *testing.T) { testData := []struct { traceID string spanID string parentSpanID string flags string expected trace.SpanContextConfig err error debug bool }{ { traceID128Str, spanID64Str, deprecatedParentSpanID, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, false, }, { traceID64Str, spanID64Str, deprecatedParentSpanID, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, false, }, { traceID60Str, spanID60Str, deprecatedParentSpanID, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, false, }, { traceID128Str, spanID64Str, deprecatedParentSpanID, "3", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, true, }, { // if we didn't set sampled bit when debug bit is 1, then assuming it's not sampled traceID128Str, spanID64Str, deprecatedParentSpanID, "2", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x00, }, nil, false, }, { // ignore firehose bit since we don't really have this feature in otel span context traceID128Str, spanID64Str, deprecatedParentSpanID, "8", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x00, }, nil, false, }, { traceID128Str, spanID64Str, deprecatedParentSpanID, "9", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, false, }, { traceID128Str, spanID64Str, "wired stuff", "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, false, }, { fmt.Sprintf("%32s", "This_is_a_string_len_64"), spanID64Str, deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errMalformedTraceID, false, }, { "0000000000000007b00000000000001c8", spanID64Str, deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errInvalidTraceIDLength, false, }, { traceID128Str, fmt.Sprintf("%16s", "wiredspanid"), deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errMalformedSpanID, false, }, { traceID128Str, "00000000000000010", deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errInvalidSpanIDLength, false, }, { // reject invalid traceID(0) and spanID(0) zeroTraceIDStr, zeroSpanIDStr, deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errMalformedTraceID, false, }, { // reject invalid traceID(0) and spanID(0) traceID128Str, zeroSpanIDStr, deprecatedParentSpanID, "1", trace.SpanContextConfig{}, errMalformedSpanID, false, }, } for _, test := range testData { headerVal := strings.Join([]string{test.traceID, test.spanID, test.parentSpanID, test.flags}, separator) ctx, sc, err := extract(context.Background(), headerVal) info := []interface{}{ "trace ID: %q, span ID: %q, parent span ID: %q, sampled: %q, flags: %q", test.traceID, test.spanID, test.parentSpanID, test.flags, } if !assert.Equal(t, test.err, err, info...) { continue } assert.Equal(t, trace.NewSpanContext(test.expected), sc, info...) assert.Equal(t, test.debug, debugFromContext(ctx)) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/jaeger/version.go000066400000000000000000000017771443314701600274510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaeger // import "go.opentelemetry.io/contrib/propagators/jaeger" // Version is the current release version of the Jaeger propagator. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/000077500000000000000000000000001443314701600263465ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/README.md000066400000000000000000000021721443314701600276270ustar00rootroot00000000000000# OpenCensus Binary Propagation Format ## The Problem The [ocgrpc](https://github.com/census-instrumentation/opencensus-go/tree/master/plugin/ocgrpc) GRPC plugin for OpenCensus is hard-coded to use a [Binary propagation format](https://github.com/census-instrumentation/opencensus-go/blob/380f4078db9f3ee20e26a08105ceecccddf872b8/trace/propagation/propagation.go). A GRPC client and server that use OpenCensus cannot easily migrate to OpenTelemetry because there will be a period of time during which one will use OpenCensus and the other will use OpenTelemetry. If both client and server export spans to the same trace backend, the server spans will not be a child of the client spans, because they are using different propagation formats. To be able to easily migrate from OpenCensus to OpenTelemetry, it is necessary to use the OpenCensus binary propagation format with OpenTelemetry. ## Usage To add the binary propagation format with otelgrpc, use the WithPropagators option to the otelgrpc Interceptors: ```golang import "go.opentelemetry.io/contrib/propagators/opencensus" opt := otelgrpc.WithPropagators(opencensus.Binary{}) ``` open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/binary.go000066400000000000000000000052631443314701600301670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package opencensus // import "go.opentelemetry.io/contrib/propagators/opencensus" import ( "context" ocpropagation "go.opencensus.io/trace/propagation" "go.opentelemetry.io/otel/bridge/opencensus" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) type key uint const binaryKey key = 0 // binaryHeader is the same as traceContextKey is in opencensus: // https://github.com/census-instrumentation/opencensus-go/blob/3fb168f674736c026e623310bfccb0691e6dec8a/plugin/ocgrpc/trace_common.go#L30 const binaryHeader = "grpc-trace-bin" // Binary is an OpenTelemetry implementation of the OpenCensus grpc binary format. // Binary propagation was temporarily removed from opentelemetry. See // https://github.com/open-telemetry/opentelemetry-specification/issues/437 type Binary struct{} var _ propagation.TextMapPropagator = Binary{} // Inject injects context into the TextMapCarrier. func (b Binary) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { binaryContext := ctx.Value(binaryKey) if state, ok := binaryContext.(string); binaryContext != nil && ok { carrier.Set(binaryHeader, state) } sc := trace.SpanContextFromContext(ctx) if !sc.IsValid() { return } h := ocpropagation.Binary(opencensus.OTelSpanContextToOC(sc)) carrier.Set(binaryHeader, string(h)) } // Extract extracts the SpanContext from the TextMapCarrier. func (b Binary) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { state := carrier.Get(binaryHeader) if state != "" { ctx = context.WithValue(ctx, binaryKey, state) } sc := b.extract(carrier) if !sc.IsValid() { return ctx } return trace.ContextWithRemoteSpanContext(ctx, sc) } func (b Binary) extract(carrier propagation.TextMapCarrier) trace.SpanContext { h := carrier.Get(binaryHeader) if h == "" { return trace.SpanContext{} } ocContext, ok := ocpropagation.FromBinary([]byte(h)) if !ok { return trace.SpanContext{} } return opencensus.OCSpanContextToOTel(ocContext) } // Fields returns the fields that this propagator modifies. func (b Binary) Fields() []string { return []string{binaryHeader} } open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/binary_test.go000066400000000000000000000102241443314701600312170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package opencensus import ( "context" "fmt" "net/http" "testing" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) var ( traceID = trace.TraceID([16]byte{14, 54, 12}) spanID = trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1}) childSpanID = trace.SpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 2}) headerFmt = "\x00\x00\x0e6\f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00%s\x02%s" ) func TestFields(t *testing.T) { b := Binary{} fields := b.Fields() if len(fields) != 1 { t.Fatalf("Got %d fields, expected 1", len(fields)) } if fields[0] != "grpc-trace-bin" { t.Errorf("Got fields[0] == %s, expected grpc-trace-bin", fields[0]) } } func TestInject(t *testing.T) { prop := Binary{} for _, tt := range []struct { desc string scc trace.SpanContextConfig wantHeader string }{ { desc: "empty", scc: trace.SpanContextConfig{}, wantHeader: "", }, { desc: "valid spancontext, sampled", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeader: fmt.Sprintf(headerFmt, "\x01", "\x01"), }, { desc: "valid spancontext, not sampled", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, }, wantHeader: fmt.Sprintf(headerFmt, "\x01", "\x00"), }, { desc: "valid spancontext, with unsupported bit set in traceflags", scc: trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0xff, }, wantHeader: fmt.Sprintf(headerFmt, "\x01", "\x01"), }, { desc: "invalid spancontext", scc: trace.SpanContextConfig{}, wantHeader: "", }, } { t.Run(tt.desc, func(t *testing.T) { header := http.Header{} ctx := context.Background() if sc := trace.NewSpanContext(tt.scc); sc.IsValid() { ctx = trace.ContextWithRemoteSpanContext(ctx, sc) } prop.Inject(ctx, propagation.HeaderCarrier(header)) gotHeader := header.Get("grpc-trace-bin") if gotHeader != tt.wantHeader { t.Errorf("Got header = %q, want %q", gotHeader, tt.wantHeader) } }) } } func TestExtract(t *testing.T) { prop := Binary{} for _, tt := range []struct { desc string header string wantScc trace.SpanContextConfig }{ { desc: "empty", header: "", wantScc: trace.SpanContextConfig{}, }, { desc: "header not binary", header: "5435j345io34t5904w3jt894j3t854w89tp95jgt9", wantScc: trace.SpanContextConfig{}, }, { desc: "valid binary header", header: fmt.Sprintf(headerFmt, "\x02", "\x00"), wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: childSpanID, }, }, { desc: "valid binary and sampled", header: fmt.Sprintf(headerFmt, "\x02", "\x01"), wantScc: trace.SpanContextConfig{ TraceID: traceID, SpanID: childSpanID, TraceFlags: trace.FlagsSampled, }, }, } { t.Run(tt.desc, func(t *testing.T) { header := http.Header{ http.CanonicalHeaderKey("grpc-trace-bin"): []string{tt.header}, } ctx := context.Background() ctx = prop.Extract(ctx, propagation.HeaderCarrier(header)) gotSc := trace.SpanContextFromContext(ctx) comparer := cmp.Comparer(func(a, b trace.SpanContext) bool { // Do not compare remote field, it is unset on empty // SpanContext. newA := a.WithRemote(b.IsRemote()) return newA.Equal(b) }) if diff := cmp.Diff(gotSc, trace.NewSpanContext(tt.wantScc), comparer); diff != "" { t.Errorf("%s: -got +want %s", tt.desc, diff) } }) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/000077500000000000000000000000001443314701600301645ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/README.md000066400000000000000000000024741443314701600314520ustar00rootroot00000000000000# OpenCensus binary propagation example The server uses OpenTelemetry with the OpenCensus binary propagation format. The client uses OpenCensus, which is hard-coded to use the OpenCensus binary propagation format. Since the client and server use the same propagation format, the ParentSpanID from the server spans should match the SpanID from the client spans, and both should share the same TraceID. ### Usage First, start the opentelemetry server: ```bash go run opentelemetry_server/server.go ``` In another shell, start the OpenCensus client: ```bash go run opencensus_client/client.go ``` ### Example Client Output ``` Configuring OpenCensus, and registering the Print exporter. TraceID: 9d59b1bdbde34cdaac6cfb5b8f3c4685 SpanID: 07733a2559ef492d ... Greeting: Hello world ``` Note that there is no ParentSpanID listed in the client. ### Example Server Output ``` Registering opentelemetry stdout exporter. Starting the GRPC server, and using the OpenCensus binary propagation format. [ { "SpanContext": { "TraceID": "9d59b1bdbde34cdaac6cfb5b8f3c4685", "SpanID": "94738571415fdb63", "TraceFlags": 1 }, "ParentSpanID": "07733a2559ef492d", ... } ] ``` The TraceID matches the TraceID from the OpenCensus client span, and the ParentSpanID matches the SpanID of the OpenCensus client span. open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/go.mod000066400000000000000000000024531443314701600312760ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/opencensus/examples go 1.19 require ( go.opencensus.io v0.24.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 go.opentelemetry.io/contrib/propagators/opencensus v0.42.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 google.golang.org/grpc v1.55.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.3 // indirect go.opentelemetry.io/otel/bridge/opencensus v0.39.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/protobuf v1.30.0 // indirect ) replace ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => ../../../instrumentation/google.golang.org/grpc/otelgrpc go.opentelemetry.io/contrib/propagators/opencensus => ../ ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/go.sum000066400000000000000000000321711443314701600313230ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/bridge/opencensus v0.39.0 h1:YHivttTaDhbZIHuPlg1sWsy2P5gj57vzqPfkHItgbwQ= go.opentelemetry.io/otel/bridge/opencensus v0.39.0/go.mod h1:vZ4537pNjFDXEx//WldAR6Ro2LC8wwmFC76njAXwNPE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/opencensus_client/000077500000000000000000000000001443314701600337045ustar00rootroot00000000000000client.go000066400000000000000000000034711443314701600354370ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/opencensus_client// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "log" "os" "time" "go.opencensus.io/examples/exporter" pb "go.opencensus.io/examples/grpc/proto" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) const ( address = "localhost:50051" defaultName = "world" ) func main() { log.Println("Configuring OpenCensus, and registering the Print exporter.") trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) trace.RegisterExporter(&exporter.PrintExporter{}) // Set up a connection to the server with the OpenCensus // stats handler to enable tracing. conn, err := grpc.Dial(address, grpc.WithStatsHandler(&ocgrpc.ClientHandler{}), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("Cannot connect: %v", err) } defer conn.Close() c := pb.NewGreeterClient(conn) // Contact the server and print out its response. name := defaultName if len(os.Args) > 1 { name = os.Args[1] } for { r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name}) if err != nil { log.Printf("Could not greet: %v", err) } else { log.Printf("Greeting: %s", r.Message) } time.Sleep(2 * time.Second) } } opentelemetry_server/000077500000000000000000000000001443314701600343675ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examplesserver.go000066400000000000000000000051121443314701600362230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/examples/opentelemetry_server// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main // import "go.opentelemetry.io/otel/bridge/opencensus/examples/grpc/server" import ( "context" "log" "math/rand" "net" "time" pb "go.opencensus.io/examples/grpc/proto" "go.opencensus.io/trace" "google.golang.org/grpc" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/contrib/propagators/opencensus" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) const port = ":50051" // server is used to implement helloworld.GreeterServer. type server struct{} // SayHello implements helloworld.GreeterServer. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { _, span := trace.StartSpan(ctx, "sleep") time.Sleep(time.Duration(rand.Float64() * float64(time.Second))) span.End() return &pb.HelloReply{Message: "Hello " + in.Name}, nil } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("Failed to listen: %v", err) } log.Println("Registering OpenTelemetry stdout exporter.") otExporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { log.Fatal(err) } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(otExporter), sdktrace.WithSampler(sdktrace.AlwaysSample()), ) defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Printf("Error shutting down tracer provider: %v", err) } }() otel.SetTracerProvider(tp) // Set up a new server with the OpenCensus // handler to enable tracing. log.Println("Starting the GRPC server, and using the OpenCensus binary propagation format.") s := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(otelgrpc.WithPropagators(opencensus.Binary{}))), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(otelgrpc.WithPropagators(opencensus.Binary{})))) pb.RegisterGreeterServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("Failed to serve: %v", err) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/go.mod000066400000000000000000000012001443314701600274450ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/opencensus go 1.19 require ( github.com/google/go-cmp v0.5.9 go.opencensus.io v0.24.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/bridge/opencensus v0.39.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect golang.org/x/sys v0.8.0 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/go.sum000066400000000000000000000263271443314701600275130ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/bridge/opencensus v0.39.0 h1:YHivttTaDhbZIHuPlg1sWsy2P5gj57vzqPfkHItgbwQ= go.opentelemetry.io/otel/bridge/opencensus v0.39.0/go.mod h1:vZ4537pNjFDXEx//WldAR6Ro2LC8wwmFC76njAXwNPE= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= open-telemetry-opentelemetry-go-contrib-2135499/propagators/opencensus/version.go000066400000000000000000000020131443314701600303560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package opencensus // import "go.opentelemetry.io/contrib/propagators/opencensus" // Version is the current release version of the OpenCensus propagator. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/000077500000000000000000000000001443314701600246065ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/doc.go000066400000000000000000000014271443314701600257060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package ot implements the ot-tracer-* propagator used by the default Tracer // implementation from the OpenTracing project. package ot // import "go.opentelemetry.io/contrib/propagators/ot" open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/go.mod000066400000000000000000000010251443314701600257120ustar00rootroot00000000000000module go.opentelemetry.io/contrib/propagators/ot go 1.19 require ( github.com/google/go-cmp v0.5.9 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 go.uber.org/multierr v1.11.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/go.sum000066400000000000000000000041561443314701600257470ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/ot_data_test.go000066400000000000000000000153101443314701600276070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot_test import ( "strings" "go.opentelemetry.io/otel/trace" ) const ( traceID16Str = "a3ce929d0e0e4736" traceID32Str = "a1ce929d0e0e4736a3ce929d0e0e4736" spanIDStr = "00f067aa0ba902b7" traceIDHeader = "ot-tracer-traceid" spanIDHeader = "ot-tracer-spanid" sampledHeader = "ot-tracer-sampled" baggageKey = "test" baggageValue = "value123" baggageHeader = "ot-baggage-test" baggageKey2 = "test2" baggageValue2 = "value456" baggageHeader2 = "ot-baggage-test2" ) var ( traceID16 = trace.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} traceID32 = trace.TraceID{0xa1, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} spanID = trace.SpanID{0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7} emptyBaggage = map[string]string{} baggageSet = map[string]string{ baggageKey: baggageValue, } baggageSet2 = map[string]string{ baggageKey: baggageValue, baggageKey2: baggageValue2, } ) type extractTest struct { name string headers map[string]string expected trace.SpanContextConfig baggage map[string]string } var extractHeaders = []extractTest{ { "empty", map[string]string{}, trace.SpanContextConfig{}, emptyBaggage, }, { "sampling state not sample", map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "0", }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, emptyBaggage, }, { "sampling state sampled", map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "1", baggageHeader: baggageValue, }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, baggageSet, }, { "baggage multiple values", map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "0", baggageHeader: baggageValue, baggageHeader2: baggageValue2, }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, baggageSet2, }, { "left padding 64 bit trace ID", map[string]string{ traceIDHeader: traceID16Str, spanIDHeader: spanIDStr, sampledHeader: "1", }, trace.SpanContextConfig{ TraceID: traceID16, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, emptyBaggage, }, { "128 bit trace ID", map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "1", }, trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, emptyBaggage, }, } var invalidExtractHeaders = []extractTest{ { name: "trace ID length > 32", headers: map[string]string{ traceIDHeader: traceID32Str + "0000", spanIDHeader: spanIDStr, sampledHeader: "1", }, }, { name: "trace ID length is not 32 or 16", headers: map[string]string{ traceIDHeader: "1234567890abcd01234", spanIDHeader: spanIDStr, sampledHeader: "1", }, }, { name: "span ID length is not 16 or 32", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr + "0000", sampledHeader: "1", }, }, { name: "invalid trace ID", headers: map[string]string{ traceIDHeader: "zcd00v0000000000a3ce929d0e0e4736", spanIDHeader: spanIDStr, sampledHeader: "1", }, }, { name: "invalid span ID", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: "00f0wiredba902b7", sampledHeader: "1", }, }, { name: "invalid sampled", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "wired", }, }, { name: "invalid baggage key", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "1", "ot-baggage-d–76": "test", }, expected: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "invalid baggage value", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "1", baggageHeader: "øtel", }, expected: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "invalid baggage result (too large)", headers: map[string]string{ traceIDHeader: traceID32Str, spanIDHeader: spanIDStr, sampledHeader: "1", baggageHeader: strings.Repeat("s", 8188), }, expected: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "missing headers", headers: map[string]string{}, }, { name: "empty header value", headers: map[string]string{ traceIDHeader: "", }, }, } type injectTest struct { name string sc trace.SpanContextConfig wantHeaders map[string]string baggage map[string]string } var injectHeaders = []injectTest{ { name: "sampled", sc: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, wantHeaders: map[string]string{ traceIDHeader: traceID16Str, spanIDHeader: spanIDStr, sampledHeader: "true", }, }, { name: "not sampled", sc: trace.SpanContextConfig{ TraceID: traceID32, SpanID: spanID, }, baggage: map[string]string{ baggageKey: baggageValue, baggageKey2: baggageValue2, }, wantHeaders: map[string]string{ traceIDHeader: traceID16Str, spanIDHeader: spanIDStr, sampledHeader: "false", baggageHeader: baggageValue, baggageHeader2: baggageValue2, }, }, } var invalidInjectHeaders = []injectTest{ { name: "empty", sc: trace.SpanContextConfig{}, }, { name: "missing traceID", sc: trace.SpanContextConfig{ SpanID: spanID, TraceFlags: trace.FlagsSampled, }, }, { name: "missing spanID", sc: trace.SpanContextConfig{ TraceID: traceID32, TraceFlags: trace.FlagsSampled, }, }, { name: "missing both traceID and spanID", sc: trace.SpanContextConfig{ TraceFlags: trace.FlagsSampled, }, }, } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/ot_example_test.go000066400000000000000000000014571443314701600303400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot_test import ( "go.opentelemetry.io/contrib/propagators/ot" "go.opentelemetry.io/otel" ) func ExampleOT() { otPropagator := ot.OT{} // register ot propagator otel.SetTextMapPropagator(otPropagator) } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/ot_integration_test.go000066400000000000000000000066671443314701600312400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot_test import ( "context" "net/http" "testing" "github.com/google/go-cmp/cmp" "go.opentelemetry.io/contrib/propagators/ot" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) func TestExtractOT(t *testing.T) { testGroup := []struct { name string testcases []extractTest }{ { name: "valid test case", testcases: extractHeaders, }, { name: "invalid test case", testcases: invalidExtractHeaders, }, } for _, tg := range testGroup { propagator := ot.OT{} for _, tc := range tg.testcases { t.Run(tc.name, func(t *testing.T) { h := make(http.Header, len(tc.headers)) for k, v := range tc.headers { h.Set(k, v) } ctx := context.Background() ctx = propagator.Extract(ctx, propagation.HeaderCarrier(h)) resSc := trace.SpanContextFromContext(ctx) comparer := cmp.Comparer(func(a, b trace.SpanContext) bool { // Do not compare remote field, it is unset on empty // SpanContext. newA := a.WithRemote(b.IsRemote()) return newA.Equal(b) }) if diff := cmp.Diff(resSc, trace.NewSpanContext(tc.expected), comparer); diff != "" { t.Errorf("%s: %s: -got +want %s", tg.name, tc.name, diff) } members := baggage.FromContext(ctx).Members() actualBaggage := map[string]string{} for _, m := range members { actualBaggage[m.Key()] = m.Value() } if diff := cmp.Diff(tc.baggage, actualBaggage); tc.baggage != nil && diff != "" { t.Errorf("%s: %s: -got +want %s", tg.name, tc.name, diff) } }) } } } func TestInjectOT(t *testing.T) { testGroup := []struct { name string testcases []injectTest }{ { name: "valid test case", testcases: injectHeaders, }, { name: "invalid test case", testcases: invalidInjectHeaders, }, } for _, tg := range testGroup { for _, tc := range tg.testcases { propagator := ot.OT{} t.Run(tc.name, func(t *testing.T) { members := []baggage.Member{} for k, v := range tc.baggage { m, err := baggage.NewMember(k, v) if err != nil { t.Errorf("%s: %s, unexpected error creating baggage member: %s", tg.name, tc.name, err.Error()) } members = append(members, m) } bag, err := baggage.New(members...) if err != nil { t.Errorf("%s: %s, unexpected error creating baggage: %s", tg.name, tc.name, err.Error()) } ctx := baggage.ContextWithBaggage(context.Background(), bag) ctx = trace.ContextWithSpanContext(ctx, trace.NewSpanContext(tc.sc)) header := http.Header{} propagator.Inject(ctx, propagation.HeaderCarrier(header)) for h, v := range tc.wantHeaders { result, want := header.Get(h), v if diff := cmp.Diff(result, want); diff != "" { t.Errorf("%s: %s, header=%s: -got +want %s", tg.name, tc.name, h, diff) } } }) } } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/ot_propagator.go000066400000000000000000000116551443314701600300250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot // import "go.opentelemetry.io/contrib/propagators/ot" import ( "context" "errors" "fmt" "strings" "go.uber.org/multierr" "go.opentelemetry.io/otel/baggage" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" ) const ( // Default OT Header names. traceIDHeader = "ot-tracer-traceid" spanIDHeader = "ot-tracer-spanid" sampledHeader = "ot-tracer-sampled" baggageHeaderPrefix = "ot-baggage-" otTraceIDPadding = "0000000000000000" traceID64BitsWidth = 64 / 4 // 16 hex character Trace ID. ) var ( empty = trace.SpanContext{} errInvalidSampledHeader = errors.New("invalid OT Sampled header found") errInvalidTraceIDHeader = errors.New("invalid OT traceID header found") errInvalidSpanIDHeader = errors.New("invalid OT spanID header found") errInvalidScope = errors.New("require either both traceID and spanID or none") ) // OT propagator serializes SpanContext to/from ot-trace-* headers. type OT struct { } var _ propagation.TextMapPropagator = OT{} // Inject injects a context into the carrier as OT headers. // NOTE: In order to interop with systems that use the OT header format, trace ids MUST be 64-bits. func (o OT) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { sc := trace.SpanFromContext(ctx).SpanContext() if !sc.TraceID().IsValid() || !sc.SpanID().IsValid() { // don't bother injecting anything if either trace or span IDs are not valid return } carrier.Set(traceIDHeader, sc.TraceID().String()[len(sc.TraceID().String())-traceID64BitsWidth:]) carrier.Set(spanIDHeader, sc.SpanID().String()) if sc.IsSampled() { carrier.Set(sampledHeader, "true") } else { carrier.Set(sampledHeader, "false") } for _, m := range baggage.FromContext(ctx).Members() { carrier.Set(fmt.Sprintf("%s%s", baggageHeaderPrefix, m.Key()), m.Value()) } } // Extract extracts a context from the carrier if it contains OT headers. func (o OT) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { var ( sc trace.SpanContext err error ) var ( traceID = carrier.Get(traceIDHeader) spanID = carrier.Get(spanIDHeader) sampled = carrier.Get(sampledHeader) ) sc, err = extract(traceID, spanID, sampled) if err != nil || !sc.IsValid() { return ctx } bags, err := extractBags(carrier) if err != nil { return trace.ContextWithRemoteSpanContext(ctx, sc) } ctx = baggage.ContextWithBaggage(ctx, bags) return trace.ContextWithRemoteSpanContext(ctx, sc) } // Fields returns the OT header keys whose values are set with Inject. func (o OT) Fields() []string { return []string{traceIDHeader, spanIDHeader, sampledHeader} } // extractBags extracts OpenTracing baggage information from carrier. func extractBags(carrier propagation.TextMapCarrier) (baggage.Baggage, error) { var err error var members []baggage.Member for _, key := range carrier.Keys() { lowerKey := strings.ToLower(key) if !strings.HasPrefix(lowerKey, baggageHeaderPrefix) { continue } strippedKey := strings.TrimPrefix(lowerKey, baggageHeaderPrefix) member, e := baggage.NewMember(strippedKey, carrier.Get(key)) if e != nil { err = multierr.Append(err, e) continue } members = append(members, member) } bags, e := baggage.New(members...) if err != nil { return bags, multierr.Append(err, e) } return bags, err } // extract reconstructs a SpanContext from header values based on OT // headers. func extract(traceID, spanID, sampled string) (trace.SpanContext, error) { var ( err error requiredCount int scc = trace.SpanContextConfig{} ) switch strings.ToLower(sampled) { case "0", "false": // Zero value for TraceFlags sample bit is unset. case "1", "true": scc.TraceFlags = trace.FlagsSampled case "": // Zero value for TraceFlags sample bit is unset. default: return empty, errInvalidSampledHeader } if traceID != "" { requiredCount++ id := traceID if len(traceID) == 16 { // Pad 64-bit trace IDs. id = otTraceIDPadding + traceID } if scc.TraceID, err = trace.TraceIDFromHex(id); err != nil { return empty, errInvalidTraceIDHeader } } if spanID != "" { requiredCount++ if scc.SpanID, err = trace.SpanIDFromHex(spanID); err != nil { return empty, errInvalidSpanIDHeader } } if requiredCount != 0 && requiredCount != 2 { return empty, errInvalidScope } return trace.NewSpanContext(scc), nil } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/ot_propagator_test.go000066400000000000000000000065531443314701600310650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot import ( "fmt" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/trace" ) var ( traceID = trace.TraceID{0, 0, 0, 0, 0, 0, 0, 0, 0x7b, 0, 0, 0, 0, 0, 0x1, 0xc8} traceID128Str = "00000000000000007b000000000001c8" zeroTraceIDStr = "00000000000000000000000000000000" traceID64Str = "7b000000000001c8" spanID = trace.SpanID{0, 0, 0, 0, 0, 0, 0, 0x7b} zeroSpanIDStr = "0000000000000000" spanIDStr = "000000000000007b" ) func TestOT_Extract(t *testing.T) { testData := []struct { traceID string spanID string sampled string expected trace.SpanContextConfig err error }{ { traceID128Str, spanIDStr, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, }, { traceID64Str, spanIDStr, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, }, { traceID128Str, spanIDStr, "", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x00, }, nil, }, { // if we didn't set sampled bit when debug bit is 1, then assuming it's not sampled traceID128Str, spanIDStr, "0", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x00, }, nil, }, { traceID128Str, spanIDStr, "1", trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.FlagsSampled, }, nil, }, { fmt.Sprintf("%32s", "This_is_a_string_len_64"), spanIDStr, "1", trace.SpanContextConfig{}, errInvalidTraceIDHeader, }, { "000000000007b00000000000001c8", spanIDStr, "1", trace.SpanContextConfig{}, errInvalidTraceIDHeader, }, { traceID128Str, fmt.Sprintf("%16s", "wiredspanid"), "1", trace.SpanContextConfig{}, errInvalidSpanIDHeader, }, { traceID128Str, "0000000000010", "1", trace.SpanContextConfig{}, errInvalidSpanIDHeader, }, { // reject invalid traceID(0) and spanID(0) zeroTraceIDStr, zeroSpanIDStr, "1", trace.SpanContextConfig{}, errInvalidTraceIDHeader, }, { // reject invalid spanID(0) traceID128Str, zeroSpanIDStr, "1", trace.SpanContextConfig{}, errInvalidSpanIDHeader, }, { // reject invalid spanID(0) traceID128Str, spanIDStr, "invalid", trace.SpanContextConfig{}, errInvalidSampledHeader, }, } for _, test := range testData { sc, err := extract(test.traceID, test.spanID, test.sampled) info := []interface{}{ "trace ID: %q, span ID: %q, sampled: %q", test.traceID, test.spanID, test.sampled, } if !assert.Equal(t, test.err, err, info...) { continue } assert.Equal(t, trace.NewSpanContext(test.expected), sc, info...) } } open-telemetry-opentelemetry-go-contrib-2135499/propagators/ot/version.go000066400000000000000000000017631443314701600266310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ot // import "go.opentelemetry.io/contrib/propagators/ot" // Version is the current release version of the ot propagator. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/samplers/000077500000000000000000000000001443314701600234515ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/000077500000000000000000000000001443314701600242435ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/000077500000000000000000000000001443314701600252265ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/fallback_sampler.go000066400000000000000000000064701443314701600310460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" import ( "sync" "time" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) // FallbackSampler does the sampling at a rate of 1 req/sec and 5% of additional requests. type FallbackSampler struct { lastTick time.Time quotaBalance float64 defaultSampler sdktrace.Sampler mu sync.RWMutex } // Compile time assertion that remoteSampler implements the Sampler interface. var _ sdktrace.Sampler = (*FallbackSampler)(nil) // NewFallbackSampler returns a FallbackSampler which samples 1 req/sec and additional 5% of requests using traceIDRatioBasedSampler. func NewFallbackSampler() *FallbackSampler { return &FallbackSampler{ defaultSampler: sdktrace.TraceIDRatioBased(0.05), quotaBalance: 1.0, } } // ShouldSample implements the logic of borrowing 1 req/sec and then use traceIDRatioBasedSampler to sample 5% of additional requests. func (fs *FallbackSampler) ShouldSample(parameters sdktrace.SamplingParameters) sdktrace.SamplingResult { // borrowing one request every second if fs.take(time.Now(), 1.0) { return sdktrace.SamplingResult{ Tracestate: trace.SpanContextFromContext(parameters.ParentContext).TraceState(), Decision: sdktrace.RecordAndSample, } } // traceIDRatioBasedSampler to sample 5% of additional requests every second return fs.defaultSampler.ShouldSample(parameters) } // Description returns description of the sampler being used. func (fs *FallbackSampler) Description() string { return "FallbackSampler{fallback sampling with sampling config of 1 req/sec and 5% of additional requests}" } // take consumes quota from reservoir, if any remains, then returns true. False otherwise. func (fs *FallbackSampler) take(now time.Time, itemCost float64) bool { fs.mu.Lock() defer fs.mu.Unlock() if fs.lastTick.IsZero() { fs.lastTick = now } if fs.quotaBalance >= itemCost { fs.quotaBalance -= itemCost return true } // update quota balance based on elapsed time fs.refreshQuotaBalanceLocked(now) if fs.quotaBalance >= itemCost { fs.quotaBalance -= itemCost return true } return false } // refreshQuotaBalanceLocked refreshes the quotaBalance considering elapsedTime. // It is assumed the lock is held when calling this. func (fs *FallbackSampler) refreshQuotaBalanceLocked(now time.Time) { elapsedTime := now.Sub(fs.lastTick) fs.lastTick = now // when elapsedTime is higher than 1 even then we need to keep quotaBalance // near to 1 so making elapsedTime to 1 for only borrowing 1 per second case if elapsedTime.Seconds() > 1.0 { fs.quotaBalance += 1.0 } else { // calculate how much credit have we accumulated since the last tick fs.quotaBalance += elapsedTime.Seconds() } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/fallback_sampler_test.go000066400000000000000000000042741443314701600321050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "testing" "time" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/sdk/trace" ) // assert sampling using fallback sampler. func TestSampleUsingFallbackSampler(t *testing.T) { fs := NewFallbackSampler() assert.NotEmpty(t, fs.defaultSampler) assert.Equal(t, fs.quotaBalance, 1.0) sd := fs.ShouldSample(trace.SamplingParameters{}) assert.Equal(t, trace.RecordAndSample, sd.Decision) } // assert that we only borrow 1 req/sec. func TestBorrowOnePerSecond(t *testing.T) { fs := NewFallbackSampler() borrowed := fs.take(time.Unix(1500000000, 0), 1.0) // assert that borrowing one per second assert.True(t, borrowed) borrowed = fs.take(time.Unix(1500000000, 0), 1.0) // assert that borrowing again is false during that second assert.False(t, borrowed) borrowed = fs.take(time.Unix(1500000001, 0), 1.0) // assert that borrowing again in next second assert.True(t, borrowed) } // assert that when elapsedTime is high quotaBalance should still be close to 1. func TestBorrowWithLargeElapsedTime(t *testing.T) { fs := NewFallbackSampler() borrowed := fs.take(time.Unix(1500000000, 0), 1.0) // assert that borrowing one per second assert.True(t, borrowed) // Increase the time by 9 seconds borrowed = fs.take(time.Unix(1500000009, 0), 1.0) assert.True(t, borrowed) assert.Equal(t, fs.quotaBalance, 0.0) } // assert fallback sampling description. func TestFallbackSamplerDescription(t *testing.T) { fs := NewFallbackSampler() s := fs.Description() assert.Equal(t, s, "FallbackSampler{fallback sampling with sampling config of 1 req/sec and 5% of additional requests}") } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/go.mod000066400000000000000000000010141443314701600263300ustar00rootroot00000000000000module go.opentelemetry.io/contrib/samplers/aws/xray go 1.19 require ( github.com/go-logr/logr v1.2.4 github.com/go-logr/stdr v1.2.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/go.sum000066400000000000000000000042761443314701600263720ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/000077500000000000000000000000001443314701600270425ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/client.go000066400000000000000000000144121443314701600306510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/url" ) // getSamplingRulesOutput is used to store parsed json sampling rules. type getSamplingRulesOutput struct { SamplingRuleRecords []*samplingRuleRecords `json:"SamplingRuleRecords"` } type samplingRuleRecords struct { SamplingRule *ruleProperties `json:"SamplingRule"` } // ruleProperties is the base set of properties that define a sampling rule. type ruleProperties struct { RuleName string `json:"RuleName"` ServiceType string `json:"ServiceType"` ResourceARN string `json:"ResourceARN"` Attributes map[string]string `json:"Attributes"` ServiceName string `json:"ServiceName"` Host string `json:"Host"` HTTPMethod string `json:"HTTPMethod"` URLPath string `json:"URLPath"` ReservoirSize float64 `json:"ReservoirSize"` FixedRate float64 `json:"FixedRate"` Priority int64 `json:"Priority"` Version int64 `json:"Version"` } type getSamplingTargetsInput struct { SamplingStatisticsDocuments []*samplingStatisticsDocument } // samplingStatisticsDocument is used to store current state of sampling data. type samplingStatisticsDocument struct { // A unique identifier for the service in hexadecimal. ClientID *string // The name of the sampling rule. RuleName *string // The number of requests that matched the rule. RequestCount *int64 // The number of requests borrowed. BorrowCount *int64 // The number of requests sampled using the rule. SampledCount *int64 // The current time. Timestamp *int64 } // getSamplingTargetsOutput is used to store parsed json sampling targets. type getSamplingTargetsOutput struct { LastRuleModification *float64 `json:"LastRuleModification,omitempty"` SamplingTargetDocuments []*samplingTargetDocument `json:"SamplingTargetDocuments,omitempty"` UnprocessedStatistics []*unprocessedStatistic `json:"UnprocessedStatistics,omitempty"` } // samplingTargetDocument contains updated targeted information retrieved from X-Ray service. type samplingTargetDocument struct { // The percentage of matching requests to instrument, after the reservoir is // exhausted. FixedRate *float64 `json:"FixedRate,omitempty"` // The number of seconds for the service to wait before getting sampling targets // again. Interval *int64 `json:"Interval,omitempty"` // The number of requests per second that X-Ray allocated this service. ReservoirQuota *float64 `json:"ReservoirQuota,omitempty"` // The reservoir quota expires. ReservoirQuotaTTL *float64 `json:"ReservoirQuotaTTL,omitempty"` // The name of the sampling rule. RuleName *string `json:"RuleName,omitempty"` } type unprocessedStatistic struct { ErrorCode *string `json:"ErrorCode,omitempty"` Message *string `json:"Message,omitempty"` RuleName *string `json:"RuleName,omitempty"` } type xrayClient struct { // HTTP client for sending sampling requests to the collector. httpClient *http.Client // Resolved URL to call getSamplingRules API. samplingRulesURL string // Resolved URL to call getSamplingTargets API. samplingTargetsURL string } // newClient returns an HTTP client with proxy endpoint. func newClient(endpoint url.URL) (client *xrayClient, err error) { // Construct resolved URLs for getSamplingRules and getSamplingTargets API calls. endpoint.Path = "/GetSamplingRules" samplingRulesURL := endpoint endpoint.Path = "/SamplingTargets" samplingTargetsURL := endpoint return &xrayClient{ httpClient: &http.Client{}, samplingRulesURL: samplingRulesURL.String(), samplingTargetsURL: samplingTargetsURL.String(), }, nil } // getSamplingRules calls the collector(aws proxy enabled) for sampling rules. func (c *xrayClient) getSamplingRules(ctx context.Context) (*getSamplingRulesOutput, error) { emptySamplingRulesInputJSON := []byte(`{"NextToken": null}`) body := bytes.NewReader(emptySamplingRulesInputJSON) req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.samplingRulesURL, body) if err != nil { return nil, fmt.Errorf("xray client: failed to create http request: %w", err) } output, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("xray client: unable to retrieve sampling settings: %w", err) } defer output.Body.Close() var samplingRulesOutput *getSamplingRulesOutput if err := json.NewDecoder(output.Body).Decode(&samplingRulesOutput); err != nil { return nil, fmt.Errorf("xray client: unable to unmarshal the response body: %w", err) } return samplingRulesOutput, nil } // getSamplingTargets calls the collector(aws proxy enabled) for sampling targets. func (c *xrayClient) getSamplingTargets(ctx context.Context, s []*samplingStatisticsDocument) (*getSamplingTargetsOutput, error) { statistics := getSamplingTargetsInput{ SamplingStatisticsDocuments: s, } statisticsByte, err := json.Marshal(statistics) if err != nil { return nil, err } body := bytes.NewReader(statisticsByte) req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.samplingTargetsURL, body) if err != nil { return nil, fmt.Errorf("xray client: failed to create http request: %w", err) } output, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("xray client: unable to retrieve sampling settings: %w", err) } defer output.Body.Close() var samplingTargetsOutput *getSamplingTargetsOutput if err := json.NewDecoder(output.Body).Decode(&samplingTargetsOutput); err != nil { return nil, fmt.Errorf("xray client: unable to unmarshal the response body: %w", err) } return samplingTargetsOutput, nil } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/client_test.go000066400000000000000000000206051443314701600317110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal import ( "context" "net/http" "net/http/httptest" "net/url" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func createTestClient(t *testing.T, body []byte) *xrayClient { testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, _ *http.Request) { _, err := res.Write(body) require.NoError(t, err) })) t.Cleanup(testServer.Close) u, err := url.Parse(testServer.URL) require.NoError(t, err) client, err := newClient(*u) require.NoError(t, err) return client } func TestGetSamplingRules(t *testing.T) { body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/Default", "RuleName": "Default", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } }, { "CreatedAt": 1637691613, "ModifiedAt": 1643748669, "SamplingRule": { "Attributes": {}, "FixedRate": 0.09, "HTTPMethod": "GET", "Host": "*", "Priority": 1, "ReservoirSize": 3, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/test-rule", "RuleName": "test-rule", "ServiceName": "test-rule", "ServiceType": "local", "URLPath": "/aws-sdk-call", "Version": 1 } }, { "CreatedAt": 1639446197, "ModifiedAt": 1639446197, "SamplingRule": { "Attributes": {}, "FixedRate": 0.09, "HTTPMethod": "*", "Host": "*", "Priority": 100, "ReservoirSize": 100, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/test-rule-1", "RuleName": "test-rule-1", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } } ] }`) ctx := context.Background() client := createTestClient(t, body) samplingRules, err := client.getSamplingRules(ctx) require.NoError(t, err) assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.RuleName, "Default") assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.ServiceType, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.Host, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.URLPath, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.ReservoirSize, 60.0) assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.FixedRate, 0.5) assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.RuleName, "test-rule") assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.ServiceType, "local") assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.Host, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.URLPath, "/aws-sdk-call") assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.ReservoirSize, 3.0) assert.Equal(t, samplingRules.SamplingRuleRecords[1].SamplingRule.FixedRate, 0.09) assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.RuleName, "test-rule-1") assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.ServiceType, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.Host, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.URLPath, "*") assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.ReservoirSize, 100.0) assert.Equal(t, samplingRules.SamplingRuleRecords[2].SamplingRule.FixedRate, 0.09) } func TestGetSamplingRulesWithMissingValues(t *testing.T) { body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/Default", "RuleName": "Default", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } } ] }`) ctx := context.Background() client := createTestClient(t, body) samplingRules, err := client.getSamplingRules(ctx) require.NoError(t, err) // Priority and ReservoirSize are missing in API response so they are assigned as nil assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.Priority, int64(0)) assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.ReservoirSize, 0.0) // other values are stored as expected assert.Equal(t, samplingRules.SamplingRuleRecords[0].SamplingRule.RuleName, "Default") } func TestGetSamplingTargets(t *testing.T) { body := []byte(`{ "LastRuleModification": 123456, "SamplingTargetDocuments": [ { "FixedRate": 5, "Interval": 5, "ReservoirQuota": 3, "ReservoirQuotaTTL": 456789, "RuleName": "r1" } ], "UnprocessedStatistics": [ { "ErrorCode": "200", "Message": "ok", "RuleName": "r1" } ] }`) ctx := context.Background() client := createTestClient(t, body) samplingTragets, err := client.getSamplingTargets(ctx, nil) require.NoError(t, err) assert.Equal(t, *samplingTragets.LastRuleModification, float64(123456)) assert.Equal(t, *samplingTragets.SamplingTargetDocuments[0].FixedRate, float64(5)) assert.Equal(t, *samplingTragets.SamplingTargetDocuments[0].Interval, int64(5)) assert.Equal(t, *samplingTragets.SamplingTargetDocuments[0].ReservoirQuota, 3.0) assert.Equal(t, *samplingTragets.SamplingTargetDocuments[0].ReservoirQuotaTTL, float64(456789)) assert.Equal(t, *samplingTragets.SamplingTargetDocuments[0].RuleName, "r1") assert.Equal(t, *samplingTragets.UnprocessedStatistics[0].RuleName, "r1") assert.Equal(t, *samplingTragets.UnprocessedStatistics[0].ErrorCode, "200") assert.Equal(t, *samplingTragets.UnprocessedStatistics[0].Message, "ok") } func TestGetSamplingTargetsMissingValues(t *testing.T) { body := []byte(`{ "LastRuleModification": 123456, "SamplingTargetDocuments": [ { "FixedRate": 5, "ReservoirQuotaTTL": 456789, "RuleName": "r1" } ], "UnprocessedStatistics": [ { "ErrorCode": "200", "Message": "ok", "RuleName": "r1" } ] }`) ctx := context.Background() client := createTestClient(t, body) samplingTragets, err := client.getSamplingTargets(ctx, nil) require.NoError(t, err) assert.Nil(t, samplingTragets.SamplingTargetDocuments[0].Interval) assert.Nil(t, samplingTragets.SamplingTargetDocuments[0].ReservoirQuota) } func TestNilContext(t *testing.T) { client := createTestClient(t, []byte(``)) samplingRulesOutput, err := client.getSamplingRules(context.TODO()) require.Error(t, err) require.Nil(t, samplingRulesOutput) samplingTargetsOutput, err := client.getSamplingTargets(context.TODO(), nil) require.Error(t, err) require.Nil(t, samplingTargetsOutput) } func TestNewClient(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1:2020") require.NoError(t, err) xrayClient, err := newClient(*endpoint) require.NoError(t, err) assert.Equal(t, "http://127.0.0.1:2020/GetSamplingRules", xrayClient.samplingRulesURL) assert.Equal(t, "http://127.0.0.1:2020/SamplingTargets", xrayClient.samplingTargetsURL) } func TestEndpointIsNotReachable(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1:2020") require.NoError(t, err) client, err := newClient(*endpoint) require.NoError(t, err) _, err = client.getSamplingRules(context.Background()) assert.Error(t, err) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/clock.go000066400000000000000000000024111443314701600304620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "time" ) // clock represents a time keeper that returns its version of the current time. type clock interface { now() time.Time } // defaultClock wraps the standard time package. type defaultClock struct{} // now returns current time according to the standard time package. func (t *defaultClock) now() time.Time { return time.Now() } // mockClock is a time keeper that returns a fixed time. type mockClock struct { nowTime int64 nowNanos int64 } // now function returns the fixed time value stored in c. func (c *mockClock) now() time.Time { return time.Unix(c.nowTime, c.nowNanos) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/manifest.go000066400000000000000000000263251443314701600312070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "context" crypto "crypto/rand" "fmt" "math" "net/url" "reflect" "sort" "strings" "sync" "time" "github.com/go-logr/logr" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) const manifestTTL = 3600 const version = 1 // Manifest represents a full sampling ruleset and provides // options for configuring Logger, Clock and xrayClient. type Manifest struct { Rules []Rule SamplingTargetsPollingInterval time.Duration refreshedAt time.Time xrayClient *xrayClient clientID *string logger logr.Logger clock clock mu sync.RWMutex } // NewManifest return manifest object configured the passed with logging and an xrayClient // configured to address addr. func NewManifest(addr url.URL, logger logr.Logger) (*Manifest, error) { // Generate client for getSamplingRules and getSamplingTargets API call. client, err := newClient(addr) if err != nil { return nil, err } // Generate clientID for sampling statistics. clientID, err := generateClientID() if err != nil { return nil, err } return &Manifest{ xrayClient: client, clock: &defaultClock{}, logger: logger, SamplingTargetsPollingInterval: 10 * time.Second, clientID: clientID, }, nil } // Expired returns true if the manifest has not been successfully refreshed in // manifestTTL seconds. func (m *Manifest) Expired() bool { m.mu.RLock() defer m.mu.RUnlock() manifestLiveTime := m.refreshedAt.Add(time.Second * manifestTTL) return m.clock.now().After(manifestLiveTime) } // MatchAgainstManifestRules returns a Rule and boolean flag set as true // if rule has been match against span attributes, otherwise nil and false. func (m *Manifest) MatchAgainstManifestRules(parameters sdktrace.SamplingParameters, serviceName string, cloudPlatform string) (*Rule, bool, error) { m.mu.RLock() rules := m.Rules m.mu.RUnlock() for index := range rules { isRuleMatch, err := rules[index].appliesTo(parameters, serviceName, cloudPlatform) if err != nil { return nil, isRuleMatch, err } if isRuleMatch { return &rules[index], true, nil } } return nil, false, nil } // RefreshManifestRules writes sampling rule properties to the manifest object. func (m *Manifest) RefreshManifestRules(ctx context.Context) (err error) { // Get sampling rules from AWS X-Ray console. rules, err := m.xrayClient.getSamplingRules(ctx) if err != nil { return err } // Update the retrieved sampling rules to manifest object. m.updateRules(rules) return } // RefreshManifestTargets updates sampling targets (statistics) for each rule. func (m *Manifest) RefreshManifestTargets(ctx context.Context) (refresh bool, err error) { // Deep copy manifest object. manifest := m.deepCopy() // Generate sampling statistics based on the data in temporary manifest. statistics, err := manifest.snapshots() if err != nil { return false, err } // Return if no statistics to report. if len(statistics) == 0 { m.logger.V(5).Info("no statistics to report and not refreshing sampling targets") return false, nil } // Get sampling targets (statistics) for every expired rule from AWS X-Ray. targets, err := m.xrayClient.getSamplingTargets(ctx, statistics) if err != nil { return false, fmt.Errorf("refreshTargets: error occurred while getting sampling targets: %w", err) } m.logger.V(5).Info("successfully fetched sampling targets") // Update temporary manifest with retrieved targets (statistics) for each rule. refresh, err = manifest.updateTargets(targets) if err != nil { return refresh, err } // Find next polling interval for targets. minPoll := manifest.minimumPollingInterval() if minPoll > 0 { m.SamplingTargetsPollingInterval = minPoll } // Update centralized manifest object. m.mu.Lock() m.Rules = manifest.Rules m.mu.Unlock() return } func (m *Manifest) updateRules(rules *getSamplingRulesOutput) { tempManifest := Manifest{ Rules: []Rule{}, } for _, records := range rules.SamplingRuleRecords { if records.SamplingRule.RuleName == "" { m.logger.V(5).Info("sampling rule without rule name is not supported") continue } if records.SamplingRule.Version != version { m.logger.V(5).Info("sampling rule without Version 1 is not supported", "RuleName", records.SamplingRule.RuleName) continue } // Create the rule and store it in temporary manifest to avoid thread safety issues. tempManifest.createRule(*records.SamplingRule) } // Re-sort to fix matching priorities. tempManifest.sort() var currentRuleMap = make(map[string]Rule) m.mu.Lock() for _, rule := range m.Rules { currentRuleMap[rule.ruleProperties.RuleName] = rule } // Preserve entire Rule if newRule.ruleProperties == curRule.ruleProperties for i, newRule := range tempManifest.Rules { if curRule, ok := currentRuleMap[newRule.ruleProperties.RuleName]; ok { if reflect.DeepEqual(newRule.ruleProperties, curRule.ruleProperties) { tempManifest.Rules[i] = curRule } } } m.Rules = tempManifest.Rules m.refreshedAt = m.clock.now() m.mu.Unlock() } func (m *Manifest) createRule(ruleProp ruleProperties) { cr := reservoir{ capacity: ruleProp.ReservoirSize, } csr := Rule{ reservoir: &cr, ruleProperties: ruleProp, samplingStatistics: &samplingStatistics{}, } m.Rules = append(m.Rules, csr) } func (m *Manifest) updateTargets(targets *getSamplingTargetsOutput) (refresh bool, err error) { // Update sampling targets for each rule. for _, t := range targets.SamplingTargetDocuments { if err := m.updateReservoir(t); err != nil { return false, err } } // Consume unprocessed statistics messages. for _, s := range targets.UnprocessedStatistics { m.logger.V(5).Info( "error occurred updating sampling target for rule, code and message", "RuleName", s.RuleName, "ErrorCode", s.ErrorCode, "Message", s.Message, ) // Do not set any flags if error is unknown. if s.ErrorCode == nil || s.RuleName == nil { continue } // Set batch failure if any sampling statistics returned 5xx. if strings.HasPrefix(*s.ErrorCode, "5") { return false, fmt.Errorf("sampling statistics returned 5xx") } // Set refresh flag if any sampling statistics returned 4xx. if strings.HasPrefix(*s.ErrorCode, "4") { refresh = true } } // Set refresh flag if modifiedAt timestamp from remote is greater than ours. if remote := targets.LastRuleModification; remote != nil { // Convert unix timestamp to time.Time. lastRuleModification := time.Unix(int64(*targets.LastRuleModification), 0) if lastRuleModification.After(m.refreshedAt) { refresh = true } } return } func (m *Manifest) updateReservoir(t *samplingTargetDocument) (err error) { if t.RuleName == nil { return fmt.Errorf("invalid sampling targe: missing rule name") } if t.FixedRate == nil { return fmt.Errorf("invalid sampling target for rule %s: missing fixed rate", *t.RuleName) } for index := range m.Rules { if m.Rules[index].ruleProperties.RuleName == *t.RuleName { m.Rules[index].reservoir.refreshedAt = m.clock.now() // Update non-optional attributes from response m.Rules[index].ruleProperties.FixedRate = *t.FixedRate // Update optional attributes from response if t.ReservoirQuota != nil { m.Rules[index].reservoir.quota = *t.ReservoirQuota } if t.ReservoirQuotaTTL != nil { m.Rules[index].reservoir.expiresAt = time.Unix(int64(*t.ReservoirQuotaTTL), 0) } if t.Interval != nil { m.Rules[index].reservoir.interval = time.Duration(*t.Interval) } } } return } // snapshots takes a snapshot of sampling statistics from all rules, resetting // statistics counters in the process. func (m *Manifest) snapshots() ([]*samplingStatisticsDocument, error) { statistics := make([]*samplingStatisticsDocument, 0, len(m.Rules)) // Generate sampling statistics for user-defined rules. for index := range m.Rules { if m.Rules[index].stale(m.clock.now()) { s := m.Rules[index].snapshot(m.clock.now()) s.ClientID = m.clientID statistics = append(statistics, s) } } return statistics, nil } // deepCopy copies the m to another manifest object. func (m *Manifest) deepCopy() *Manifest { m.mu.RLock() defer m.mu.RUnlock() manifest := Manifest{ Rules: []Rule{}, } for _, rule := range m.Rules { // Deep copying rules. var tempRule Rule tempRule.ruleProperties = rule.ruleProperties // Deep copying reservoir (copying each fields of reservoir because we want to initialize new mutex values for each rule). var tempRes reservoir rule.reservoir.mu.RLock() tempRes.expiresAt = rule.reservoir.expiresAt tempRes.quota = rule.reservoir.quota tempRes.quotaBalance = rule.reservoir.quotaBalance tempRes.capacity = rule.reservoir.capacity tempRes.refreshedAt = rule.reservoir.refreshedAt tempRes.interval = rule.reservoir.interval tempRes.lastTick = rule.reservoir.lastTick rule.reservoir.mu.RUnlock() tempRule.reservoir = &tempRes // Shallow copying sampling statistics. tempRule.samplingStatistics = rule.samplingStatistics manifest.Rules = append(manifest.Rules, tempRule) } // Copying other manifest fields. manifest.SamplingTargetsPollingInterval = m.SamplingTargetsPollingInterval manifest.refreshedAt = m.refreshedAt manifest.xrayClient = m.xrayClient manifest.clientID = m.clientID manifest.logger = m.logger manifest.clock = m.clock return &manifest } // sort sorts the Rules of m first by priority and then by name. func (m *Manifest) sort() { // nolint: revive // method names are scoped by receiver. less := func(i, j int) bool { if m.Rules[i].ruleProperties.Priority == m.Rules[j].ruleProperties.Priority { return strings.Compare(m.Rules[i].ruleProperties.RuleName, m.Rules[j].ruleProperties.RuleName) < 0 } return m.Rules[i].ruleProperties.Priority < m.Rules[j].ruleProperties.Priority } sort.Slice(m.Rules, less) } // minimumPollingInterval finds the minimum polling interval for all the targets of m's Rules. func (m *Manifest) minimumPollingInterval() time.Duration { if len(m.Rules) == 0 { return time.Duration(0) } minPoll := time.Duration(math.MaxInt64) for _, rules := range m.Rules { if minPoll >= rules.reservoir.interval { minPoll = rules.reservoir.interval } } return minPoll * time.Second } // generateClientID generates random client ID. func generateClientID() (*string, error) { var r [12]byte _, err := crypto.Read(r[:]) if err != nil { return nil, fmt.Errorf("unable to generate client ID: %w", err) } id := fmt.Sprintf("%02x", r) return &id, err } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/manifest_test.go000066400000000000000000001267321443314701600322510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal import ( "context" "net/url" "testing" "time" "go.opentelemetry.io/otel/attribute" "github.com/go-logr/logr/testr" "github.com/stretchr/testify/require" sdktrace "go.opentelemetry.io/otel/sdk/trace" "github.com/stretchr/testify/assert" ) func createSamplingTargetDocument(name string, interval int64, rate, quota, ttl float64) *samplingTargetDocument { return &samplingTargetDocument{ FixedRate: &rate, Interval: &interval, ReservoirQuota: "a, ReservoirQuotaTTL: &ttl, RuleName: &name, } } // assert that new manifest has certain non-nil attributes. func TestNewManifest(t *testing.T) { logger := testr.New(t) endpoint, err := url.Parse("http://127.0.0.1:2020") require.NoError(t, err) m, err := NewManifest(*endpoint, logger) require.NoError(t, err) assert.NotEmpty(t, m.logger) assert.NotEmpty(t, m.clientID) assert.NotEmpty(t, m.SamplingTargetsPollingInterval) assert.NotNil(t, m.xrayClient) } // assert that manifest is expired. func TestExpiredManifest(t *testing.T) { clock := &mockClock{ nowTime: 10000, } m := &Manifest{ clock: clock, refreshedAt: time.Unix(3700, 0), } assert.True(t, m.Expired()) } // assert that if collector is not enabled at specified endpoint, returns an error. func TestRefreshManifestError(t *testing.T) { // collector is not running at port 2020 so expect error endpoint, err := url.Parse("http://127.0.0.1:2020") require.NoError(t, err) client, err := newClient(*endpoint) require.NoError(t, err) m := &Manifest{ xrayClient: client, } err = m.RefreshManifestRules(context.Background()) assert.Error(t, err) } // assert that manifest rule r2 is a match for sampling. func TestMatchAgainstManifestRules(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", Priority: 100, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 6, FixedRate: 0.5, Version: 1, ServiceName: "test", ResourceARN: "*", ServiceType: "local", }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } m := &Manifest{ Rules: []Rule{r1, r2}, } exp, match, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{}, "test", "local") require.True(t, match) require.NoError(t, err) // assert that manifest rule r2 is a match assert.Equal(t, *exp, r2) } // assert that if rules has attribute and span has those attribute with same value then matching will happen. func TestMatchAgainstManifestRulesAttributeMatch(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelB": "raspberry", }, }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } m := &Manifest{ Rules: []Rule{r1}, } exp, match, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{Attributes: commonLabels}, "test", "local") require.True(t, match) require.NoError(t, err) // assert that manifest rule r1 is a match assert.Equal(t, *exp, r1) } // assert that wildcard attributes will match. func TestMatchAgainstManifestRulesAttributeWildCardMatch(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "*", Attributes: map[string]string{ "labelA": "choco*", "labelB": "rasp*", }, }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } m := &Manifest{ Rules: []Rule{r1}, } exp, match, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{Attributes: commonLabels}, "test", "local") require.True(t, match) require.NoError(t, err) // assert that manifest rule r1 is a match assert.Nil(t, err) assert.Equal(t, *exp, r1) } // assert that when no known rule is match then returned rule is nil, // matched flag is false. func TestMatchAgainstManifestRulesNoMatch(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "test-no-match", ResourceARN: "*", ServiceType: "local", }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } m := &Manifest{ Rules: []Rule{r1}, } rule, isMatch, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{}, "test", "local") // assert that when no known rule is match then returned rule is nil require.NoError(t, err) assert.False(t, isMatch) assert.Nil(t, rule) } func TestRefreshManifestRules(t *testing.T) { ctx := context.Background() body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r1", "RuleName": "r1", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } }, { "CreatedAt": 1637691613, "ModifiedAt": 1643748669, "SamplingRule": { "Attributes": {}, "FixedRate": 0.09, "HTTPMethod": "GET", "Host": "*", "Priority": 1, "ReservoirSize": 3, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r2", "RuleName": "r2", "ServiceName": "test-rule", "ServiceType": "*", "URLPath": "/aws-sdk-call", "Version": 1 } }, { "CreatedAt": 1639446197, "ModifiedAt": 1639446197, "SamplingRule": { "Attributes": {}, "FixedRate": 0.09, "HTTPMethod": "*", "Host": "*", "Priority": 100, "ReservoirSize": 100, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r3", "RuleName": "r3", "ServiceName": "*", "ServiceType": "local", "URLPath": "*", "Version": 1 } } ] }`) m := &Manifest{ Rules: []Rule{}, xrayClient: createTestClient(t, body), clock: &defaultClock{}, } err := m.RefreshManifestRules(ctx) require.NoError(t, err) r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, Version: 1, FixedRate: 0.5, ServiceName: "*", ResourceARN: "*", ServiceType: "*", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 60, }, samplingStatistics: &samplingStatistics{}, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", Priority: 1, Host: "*", HTTPMethod: "GET", URLPath: "/aws-sdk-call", ReservoirSize: 3, FixedRate: 0.09, Version: 1, ServiceName: "test-rule", ResourceARN: "*", ServiceType: "*", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 3, }, samplingStatistics: &samplingStatistics{}, } r3 := Rule{ ruleProperties: ruleProperties{ RuleName: "r3", Priority: 100, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 100, FixedRate: 0.09, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "local", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 100, }, samplingStatistics: &samplingStatistics{}, } require.Len(t, m.Rules, 3) // Assert on sorting order assert.Equal(t, r2, m.Rules[0]) assert.Equal(t, r3, m.Rules[1]) assert.Equal(t, r1, m.Rules[2]) } // assert that rule with no ServiceName updates manifest successfully with empty values. func TestRefreshManifestMissingServiceName(t *testing.T) { ctx := context.Background() // rule with no ServiceName body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "XYZ", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r1", "RuleName": "r1", "ServiceType": "*", "URLPath": "*", "Version": 1 } } ] }`) m := &Manifest{ Rules: []Rule{}, xrayClient: createTestClient(t, body), clock: &defaultClock{}, } err := m.RefreshManifestRules(ctx) require.NoError(t, err) // assert on rule gets added require.Len(t, m.Rules, 1) } // assert that rule with no RuleName does not update to the manifest. func TestRefreshManifestMissingRuleName(t *testing.T) { ctx := context.Background() // rule with no RuleName body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "XYZ", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r1", "ServiceName": "test", "URLPath": "*", "Version": 1 } } ] }`) m := &Manifest{ Rules: []Rule{}, xrayClient: createTestClient(t, body), clock: &defaultClock{}, logger: testr.New(t), } err := m.RefreshManifestRules(ctx) require.NoError(t, err) // assert on rule not added require.Len(t, m.Rules, 0) } // assert that rule with version greater than one does not update to the manifest. func TestRefreshManifestIncorrectVersion(t *testing.T) { ctx := context.Background() // rule with Version 5 body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "XYZ", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r1", "RuleName": "r1", "ServiceName": "test", "ServiceType": "*", "URLPath": "*", "Version": 5 } } ] }`) m := &Manifest{ Rules: []Rule{}, xrayClient: createTestClient(t, body), clock: &defaultClock{}, logger: testr.New(t), } err := m.RefreshManifestRules(ctx) require.NoError(t, err) // assert on rule not added require.Len(t, m.Rules, 0) } // assert that 1 valid and 1 invalid rule update only valid rule gets stored to the manifest. func TestRefreshManifestAddOneInvalidRule(t *testing.T) { ctx := context.Background() // RuleName is missing from r2 body := []byte(`{ "NextToken": null, "SamplingRuleRecords": [ { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r1", "RuleName": "r1", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } }, { "CreatedAt": 0, "ModifiedAt": 1639517389, "SamplingRule": { "Attributes": {"a":"b"}, "FixedRate": 0.5, "HTTPMethod": "*", "Host": "*", "Priority": 10000, "ReservoirSize": 60, "ResourceARN": "*", "RuleARN": "arn:aws:xray:us-west-2:xxxxxxx:sampling-rule/r2", "ServiceName": "*", "ServiceType": "*", "URLPath": "*", "Version": 1 } } ] }`) r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "*", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 60, }, samplingStatistics: &samplingStatistics{}, } m := &Manifest{ Rules: []Rule{}, xrayClient: createTestClient(t, body), clock: &defaultClock{}, logger: testr.New(t), } err := m.RefreshManifestRules(ctx) require.NoError(t, err) require.Len(t, m.Rules, 1) // assert on r1 assert.Equal(t, r1, m.Rules[0]) } // assert that inactive rule so return early without doing getSamplingTargets call. func TestRefreshManifestTargetNoSnapShot(t *testing.T) { clock := &mockClock{ nowTime: 15000000, } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r3", Priority: 100, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 100, FixedRate: 0.09, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "local", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 100, }, samplingStatistics: &samplingStatistics{ matchedRequests: int64(0), }, } m := &Manifest{ Rules: []Rule{r1}, clock: clock, logger: testr.New(t), } refresh, err := m.RefreshManifestTargets(context.Background()) assert.False(t, refresh) assert.NoError(t, err) } // assert that refresh manifest targets successfully updates reservoir value for a rule. func TestRefreshManifestTargets(t *testing.T) { // RuleName is missing from r2 body := []byte(`{ "LastRuleModification": 17000000, "SamplingTargetDocuments": [ { "FixedRate": 0.06, "Interval": 25, "ReservoirQuota": 23, "ReservoirQuotaTTL": 15000000, "RuleName": "r1" } ], "UnprocessedStatistics": [ { "ErrorCode": "200", "Message": "Ok", "RuleName": "r1" } ] }`) clock := &mockClock{ nowTime: 150, } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 100, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 100, FixedRate: 0.09, Version: 1, ServiceName: "*", ResourceARN: "*", ServiceType: "local", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 100, }, samplingStatistics: &samplingStatistics{ matchedRequests: int64(5), }, } m := &Manifest{ Rules: []Rule{r1}, clock: clock, logger: testr.New(t), xrayClient: createTestClient(t, body), refreshedAt: time.Unix(18000000, 0), } refresh, err := m.RefreshManifestTargets(context.Background()) assert.False(t, refresh) require.NoError(t, err) // assert target updates require.Len(t, m.Rules, 1) assert.Equal(t, m.Rules[0].ruleProperties.FixedRate, 0.06) assert.Equal(t, m.Rules[0].reservoir.quota, 23.0) assert.Equal(t, m.Rules[0].reservoir.expiresAt, time.Unix(15000000, 0)) assert.Equal(t, m.Rules[0].reservoir.interval, time.Duration(25)) } // assert that refresh manifest targets successfully updates samplingTargetsPollingInterval. func TestRefreshManifestTargetsPollIntervalUpdateTest(t *testing.T) { body := []byte(`{ "LastRuleModification": 17000000, "SamplingTargetDocuments": [ { "FixedRate": 0.06, "Interval": 15, "ReservoirQuota": 23, "ReservoirQuotaTTL": 15000000, "RuleName": "r1" }, { "FixedRate": 0.06, "Interval": 5, "ReservoirQuota": 23, "ReservoirQuotaTTL": 15000000, "RuleName": "r2" }, { "FixedRate": 0.06, "Interval": 25, "ReservoirQuota": 23, "ReservoirQuotaTTL": 15000000, "RuleName": "r3" } ], "UnprocessedStatistics": [ { "ErrorCode": "200", "Message": "Ok", "RuleName": "r3" } ] }`) clock := &mockClock{ nowTime: 150, } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", }, samplingStatistics: &samplingStatistics{ matchedRequests: int64(5), }, reservoir: &reservoir{}, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", }, samplingStatistics: &samplingStatistics{}, reservoir: &reservoir{}, } r3 := Rule{ ruleProperties: ruleProperties{ RuleName: "r3", }, samplingStatistics: &samplingStatistics{}, reservoir: &reservoir{}, } m := &Manifest{ Rules: []Rule{r1, r2, r3}, clock: clock, logger: testr.New(t), xrayClient: createTestClient(t, body), refreshedAt: time.Unix(18000000, 0), } _, err := m.RefreshManifestTargets(context.Background()) require.NoError(t, err) // assert that sampling rules polling interval is minimum of all target intervals min(15, 5, 25) assert.Equal(t, 5*time.Second, m.SamplingTargetsPollingInterval) } // assert that a valid sampling target updates its rule. func TestUpdateTargets(t *testing.T) { targets := &getSamplingTargetsOutput{ SamplingTargetDocuments: []*samplingTargetDocument{createSamplingTargetDocument("r1", 0, 0.05, 10, 1500000060)}, } // sampling rule about to be updated with new target r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.10, }, reservoir: &reservoir{ quota: 8, refreshedAt: time.Unix(1499999990, 0), expiresAt: time.Unix(1500000010, 0), capacity: 50, }, } clock := &mockClock{ nowTime: 1500000000, } m := &Manifest{ Rules: []Rule{r1}, clock: clock, } refresh, err := m.updateTargets(targets) require.NoError(t, err) // assert refresh is false assert.False(t, refresh) // Updated sampling rule exp := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.05, }, reservoir: &reservoir{ quota: 10, refreshedAt: time.Unix(1500000000, 0), expiresAt: time.Unix(1500000060, 0), capacity: 50, }, } // assert that updated the rule targets of rule r1 assert.Equal(t, exp, m.Rules[0]) } // assert that when last rule modification time is greater than manifest refresh time we need to update manifest // out of band (async). func TestUpdateTargetsRefreshFlagTest(t *testing.T) { targetLastRuleModifiedTime := float64(1500000020) targets := &getSamplingTargetsOutput{ SamplingTargetDocuments: []*samplingTargetDocument{createSamplingTargetDocument("r1", 0, 0.05, 10, 1500000060)}, LastRuleModification: &targetLastRuleModifiedTime, } // sampling rule about to be updated with new target r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.10, }, reservoir: &reservoir{ quota: 8, refreshedAt: time.Unix(1499999990, 0), expiresAt: time.Unix(1500000010, 0), capacity: 50, }, } clock := &mockClock{ nowTime: 1500000000, } m := &Manifest{ Rules: []Rule{r1}, refreshedAt: clock.now(), clock: clock, } refresh, err := m.updateTargets(targets) require.NoError(t, err) // assert refresh is false assert.True(t, refresh) // Updated sampling rule exp := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.05, }, reservoir: &reservoir{ quota: 10, refreshedAt: time.Unix(1500000000, 0), expiresAt: time.Unix(1500000060, 0), capacity: 50, }, } // assert that updated the rule targets of rule r1 assert.Equal(t, exp, m.Rules[0]) } // unprocessed statistics error code is 5xx then updateTargets returns an error, if 4xx refresh flag set to true. func TestUpdateTargetsUnprocessedStatistics(t *testing.T) { // case for 5xx ruleName := "r1" errorCode500 := "500" unprocessedStats5xx := unprocessedStatistic{ ErrorCode: &errorCode500, RuleName: &ruleName, } targets5xx := &getSamplingTargetsOutput{ SamplingTargetDocuments: []*samplingTargetDocument{createSamplingTargetDocument(ruleName, 0, 0.05, 10, 1500000060)}, UnprocessedStatistics: []*unprocessedStatistic{&unprocessedStats5xx}, } clock := &mockClock{ nowTime: 1500000000, } m := &Manifest{ clock: clock, logger: testr.New(t), } refresh, err := m.updateTargets(targets5xx) // assert error happened since unprocessed stats has returned 5xx error code require.Error(t, err) // assert refresh is false assert.False(t, refresh) // case for 4xx errorCode400 := "400" unprocessedStats4xx := unprocessedStatistic{ ErrorCode: &errorCode400, RuleName: &ruleName, } targets4xx := &getSamplingTargetsOutput{ SamplingTargetDocuments: []*samplingTargetDocument{createSamplingTargetDocument(ruleName, 0, 0.05, 10, 1500000060)}, UnprocessedStatistics: []*unprocessedStatistic{&unprocessedStats4xx}, } refresh, err = m.updateTargets(targets4xx) // assert that no error happened since unprocessed stats has returned 4xx error code require.NoError(t, err) // assert refresh is true assert.True(t, refresh) // case when rule error code is unknown do not set any flag unprocessedStats := unprocessedStatistic{ ErrorCode: nil, RuleName: nil, } targets := &getSamplingTargetsOutput{ SamplingTargetDocuments: []*samplingTargetDocument{createSamplingTargetDocument(ruleName, 0, 0.05, 10, 1500000060)}, UnprocessedStatistics: []*unprocessedStatistic{&unprocessedStats}, } m = &Manifest{ clock: clock, logger: testr.New(t), } refresh, err = m.updateTargets(targets) require.NoError(t, err) // assert refresh is false assert.False(t, refresh) } // assert that a missing sampling rule in manifest does not update it's reservoir values. func TestUpdateReservoir(t *testing.T) { // manifest only has rule r2 but not rule with r1 which targets just received r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", FixedRate: 0.10, }, reservoir: &reservoir{ quota: 8, refreshedAt: time.Unix(1499999990, 0), expiresAt: time.Unix(1500000010, 0), capacity: 50, }, } m := &Manifest{ Rules: []Rule{r1}, } err := m.updateReservoir(createSamplingTargetDocument("r1", 0, 0.05, 10, 1500000060)) require.NoError(t, err) // assert that rule reservoir value does not get updated and still same as r1 assert.Equal(t, m.Rules[0], r1) } // assert that a sampling target with missing Fixed Rate returns an error. func TestUpdateReservoirMissingFixedRate(t *testing.T) { // manifest rule which we're trying to update with above target st r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", FixedRate: 0.10, }, reservoir: &reservoir{ quota: 8, refreshedAt: time.Unix(1499999990, 0), expiresAt: time.Unix(1500000010, 0), capacity: 50, }, } m := &Manifest{ Rules: []Rule{r1}, } st := createSamplingTargetDocument("r1", 0, 0, 10, 1500000060) st.FixedRate = nil err := m.updateReservoir(st) require.Error(t, err) } // assert that a sampling target with missing Rule Name returns an error. func TestUpdateReservoirMissingRuleName(t *testing.T) { // manifest rule which we're trying to update with above target st r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", FixedRate: 0.10, }, reservoir: &reservoir{ quota: 8, refreshedAt: time.Unix(1499999990, 0), expiresAt: time.Unix(1500000010, 0), capacity: 50, }, } m := &Manifest{ Rules: []Rule{r1}, } st := createSamplingTargetDocument("r1", 0, 0, 10, 1500000060) st.RuleName = nil err := m.updateReservoir(st) require.Error(t, err) } // assert that snapshots returns an array of valid sampling statistics. func TestSnapshots(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } time1 := clock.now().Unix() name1 := "r1" requests1 := int64(1000) sampled1 := int64(100) borrowed1 := int64(5) r1 := Rule{ ruleProperties: ruleProperties{ RuleName: name1, }, reservoir: &reservoir{ interval: 10, }, samplingStatistics: &samplingStatistics{ matchedRequests: requests1, sampledRequests: sampled1, borrowedRequests: borrowed1, }, } name2 := "r2" requests2 := int64(500) sampled2 := int64(10) borrowed2 := int64(0) r2 := Rule{ ruleProperties: ruleProperties{ RuleName: name2, }, reservoir: &reservoir{ interval: 10, }, samplingStatistics: &samplingStatistics{ matchedRequests: requests2, sampledRequests: sampled2, borrowedRequests: borrowed2, }, } id := "c1" m := &Manifest{ Rules: []Rule{r1, r2}, clientID: &id, clock: clock, } // Expected SamplingStatistics structs ss1 := samplingStatisticsDocument{ ClientID: &id, RequestCount: &requests1, RuleName: &name1, SampledCount: &sampled1, BorrowCount: &borrowed1, Timestamp: &time1, } ss2 := samplingStatisticsDocument{ ClientID: &id, RequestCount: &requests2, RuleName: &name2, SampledCount: &sampled2, BorrowCount: &borrowed2, Timestamp: &time1, } statistics, err := m.snapshots() require.NoError(t, err) // match time *statistics[0].Timestamp = 1500000000 *statistics[1].Timestamp = 1500000000 assert.Equal(t, ss1, *statistics[0]) assert.Equal(t, ss2, *statistics[1]) } // assert that fresh and inactive rules are not included in a snapshot. func TestMixedSnapshots(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } id := "c1" time1 := clock.now().Unix() // stale and active rule name1 := "r1" requests1 := int64(1000) sampled1 := int64(100) borrowed1 := int64(5) r1 := Rule{ ruleProperties: ruleProperties{ RuleName: name1, }, reservoir: &reservoir{ interval: 20, refreshedAt: time.Unix(1499999970, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: requests1, sampledRequests: sampled1, borrowedRequests: borrowed1, }, } // fresh and inactive rule name2 := "r2" requests2 := int64(0) sampled2 := int64(0) borrowed2 := int64(0) r2 := Rule{ ruleProperties: ruleProperties{ RuleName: name2, }, reservoir: &reservoir{ interval: 20, refreshedAt: time.Unix(1499999990, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: requests2, sampledRequests: sampled2, borrowedRequests: borrowed2, }, } // fresh rule name3 := "r3" requests3 := int64(1000) sampled3 := int64(100) borrowed3 := int64(5) r3 := Rule{ ruleProperties: ruleProperties{ RuleName: name3, }, reservoir: &reservoir{ interval: 20, refreshedAt: time.Unix(1499999990, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: requests3, sampledRequests: sampled3, borrowedRequests: borrowed3, }, } rules := []Rule{r1, r2, r3} m := &Manifest{ clientID: &id, clock: clock, Rules: rules, } ss1 := samplingStatisticsDocument{ ClientID: &id, RequestCount: &requests1, RuleName: &name1, SampledCount: &sampled1, BorrowCount: &borrowed1, Timestamp: &time1, } statistics, err := m.snapshots() require.NoError(t, err) // assert that only inactive rules are added to the statistics require.Len(t, statistics, 1) assert.Equal(t, ss1, *statistics[0]) } // assert that deep copy creates a new manifest object with new address space. func TestDeepCopy(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 100, Host: "http://127.0.0.0.1:2020", HTTPMethod: "POST", URLPath: "/test", ReservoirSize: 100, FixedRate: 0.09, Version: 1, ServiceName: "openTelemetry", ResourceARN: "*", ServiceType: "local", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 100, }, samplingStatistics: &samplingStatistics{ matchedRequests: int64(5), borrowedRequests: int64(1), sampledRequests: int64(3), }, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", Priority: 10, Host: "http://127.0.0.0.1:2020", HTTPMethod: "GET", URLPath: "/test/path", ReservoirSize: 100, FixedRate: 0.09, Version: 1, ServiceName: "x-ray", ResourceARN: "*", ServiceType: "local", Attributes: map[string]string{}, }, reservoir: &reservoir{ capacity: 100, }, samplingStatistics: &samplingStatistics{ matchedRequests: int64(5), borrowedRequests: int64(1), sampledRequests: int64(3), }, } clock := &mockClock{ nowTime: 1500000000, } m := &Manifest{ Rules: []Rule{r1, r2}, SamplingTargetsPollingInterval: 10 * time.Second, refreshedAt: time.Unix(1500000, 0), xrayClient: createTestClient(t, []byte(`hello world!`)), logger: testr.New(t), clock: clock, } manifest := m.deepCopy() require.Len(t, m.Rules, 2) require.Len(t, manifest.Rules, 2) assert.Equal(t, &m.xrayClient, &manifest.xrayClient) assert.NotSame(t, &m.clock, &manifest.clock) assert.NotSame(t, &m.refreshedAt, &manifest.refreshedAt) assert.NotSame(t, &m.SamplingTargetsPollingInterval, &manifest.SamplingTargetsPollingInterval) assert.NotSame(t, &m.logger, &manifest.logger) assert.NotSame(t, &m.mu, &manifest.mu) // rule properties has different address space in m and manifest assert.NotSame(t, &m.Rules[0].ruleProperties.RuleName, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.ServiceName, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.ServiceType, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.Host, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.HTTPMethod, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.URLPath, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.FixedRate, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.ReservoirSize, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.ResourceARN, &manifest.Rules[0].ruleProperties.RuleName) assert.NotSame(t, &m.Rules[0].ruleProperties.Priority, &manifest.Rules[0].ruleProperties.Priority) assert.NotSame(t, &m.Rules[0].ruleProperties.Version, &manifest.Rules[0].ruleProperties.Version) assert.NotSame(t, &m.Rules[0].ruleProperties.Attributes, &manifest.Rules[0].ruleProperties.Attributes) // reservoir has different address space in m and manifest assert.NotSame(t, &m.Rules[0].reservoir.refreshedAt, &manifest.Rules[0].reservoir.refreshedAt) assert.NotSame(t, &m.Rules[0].reservoir.expiresAt, &manifest.Rules[0].reservoir.expiresAt) assert.NotSame(t, &m.Rules[0].reservoir.lastTick, &manifest.Rules[0].reservoir.lastTick) assert.NotSame(t, &m.Rules[0].reservoir.interval, &manifest.Rules[0].reservoir.interval) assert.NotSame(t, &m.Rules[0].reservoir.capacity, &manifest.Rules[0].reservoir.capacity) assert.NotSame(t, &m.Rules[0].reservoir.quota, &manifest.Rules[0].reservoir.quota) assert.NotSame(t, &m.Rules[0].reservoir.quotaBalance, &manifest.Rules[0].reservoir.quotaBalance) // samplings statistics has same address space since it is a pointer assert.Equal(t, &m.Rules[0].samplingStatistics, &manifest.Rules[0].samplingStatistics) } // assert that sorting an unsorted array results in a sorted array - check priority. func TestSortBasedOnPriority(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 5, }, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", Priority: 6, }, } r3 := Rule{ ruleProperties: ruleProperties{ RuleName: "r3", Priority: 7, }, } // Unsorted rules array rules := []Rule{r2, r1, r3} m := &Manifest{ Rules: rules, } // Sort array m.sort() // Assert on order assert.Equal(t, r1, m.Rules[0]) assert.Equal(t, r2, m.Rules[1]) assert.Equal(t, r3, m.Rules[2]) } // assert that sorting an unsorted array results in a sorted array - check priority and rule name. func TestSortBasedOnRuleName(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 5, }, } r2 := Rule{ ruleProperties: ruleProperties{ RuleName: "r2", Priority: 5, }, } r3 := Rule{ ruleProperties: ruleProperties{ RuleName: "r3", Priority: 7, }, } // Unsorted rules array rules := []Rule{r2, r1, r3} m := &Manifest{ Rules: rules, } // Sort array m.sort() // Assert on order assert.Equal(t, r1, m.Rules[0]) assert.Equal(t, r2, m.Rules[1]) assert.Equal(t, r3, m.Rules[2]) } // asserts the minimum value of all the targets. func TestMinPollInterval(t *testing.T) { r1 := Rule{reservoir: &reservoir{interval: time.Duration(10)}} r2 := Rule{reservoir: &reservoir{interval: time.Duration(5)}} r3 := Rule{reservoir: &reservoir{interval: time.Duration(25)}} rules := []Rule{r1, r2, r3} m := &Manifest{Rules: rules} minPoll := m.minimumPollingInterval() assert.Equal(t, 5*time.Second, minPoll) } // asserts the minimum value of all the targets when some targets has 0 interval. func TestMinPollIntervalZeroCase(t *testing.T) { r1 := Rule{reservoir: &reservoir{interval: time.Duration(0)}} r2 := Rule{reservoir: &reservoir{interval: time.Duration(0)}} r3 := Rule{reservoir: &reservoir{interval: time.Duration(5)}} rules := []Rule{r1, r2, r3} m := &Manifest{Rules: rules} minPoll := m.minimumPollingInterval() assert.Equal(t, 0*time.Second, minPoll) } // asserts the minimum value of all the targets when some targets has negative interval. func TestMinPollIntervalNegativeCase(t *testing.T) { r1 := Rule{reservoir: &reservoir{interval: time.Duration(-5)}} r2 := Rule{reservoir: &reservoir{interval: time.Duration(0)}} r3 := Rule{reservoir: &reservoir{interval: time.Duration(0)}} rules := []Rule{r1, r2, r3} m := &Manifest{Rules: rules} minPoll := m.minimumPollingInterval() assert.Equal(t, -5*time.Second, minPoll) } // asserts that manifest with empty rules return 0. func TestMinPollIntervalNoRules(t *testing.T) { var rules []Rule m := &Manifest{Rules: rules} minPoll := m.minimumPollingInterval() assert.Equal(t, 0*time.Second, minPoll) } // assert that able to successfully generate the client ID. func TestGenerateClientID(t *testing.T) { clientID, err := generateClientID() require.NoError(t, err) assert.NotEmpty(t, clientID) } // validate no data race is happening when updating rule properties in manifest while matching. func TestRaceUpdatingRulesWhileMatching(t *testing.T) { // getSamplingRules response ruleRecords := samplingRuleRecords{ SamplingRule: &ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, } s := &getSamplingRulesOutput{ SamplingRuleRecords: []*samplingRuleRecords{&ruleRecords}, } // existing rule in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "test", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ expiresAt: time.Unix(14050, 0), }, } rules := []Rule{r1} clock := &mockClock{ nowTime: 1500000000, } m := &Manifest{ Rules: rules, clock: clock, } // async rule updates go func() { for i := 0; i < 100; i++ { m.updateRules(s) time.Sleep(time.Millisecond) } }() // matching logic for i := 0; i < 100; i++ { _, match, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{}, "helios", "macos") require.NoError(t, err) require.False(t, match) } } // validate no data race is happening when updating rule properties and rule targets in manifest while matching. func TestRaceUpdatingRulesAndTargetsWhileMatching(t *testing.T) { // getSamplingRules response to update existing manifest rule ruleRecords := samplingRuleRecords{ SamplingRule: &ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, } // existing rule already present in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "test", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ refreshedAt: time.Unix(13000000, 0), }, } clock := &mockClock{ nowTime: 1500000000, } rules := []Rule{r1} m := &Manifest{ Rules: rules, clock: clock, } // async rule updates go func() { for i := 0; i < 100; i++ { m.updateRules(&getSamplingRulesOutput{ SamplingRuleRecords: []*samplingRuleRecords{&ruleRecords}, }) time.Sleep(time.Millisecond) } }() // async target updates go func() { for i := 0; i < 100; i++ { manifest := m.deepCopy() err := manifest.updateReservoir(createSamplingTargetDocument("r1", 0, 0.05, 10, 13000000)) require.NoError(t, err) time.Sleep(time.Millisecond) m.mu.Lock() m.Rules = manifest.Rules m.mu.Unlock() } }() // matching logic for i := 0; i < 100; i++ { _, match, err := m.MatchAgainstManifestRules(sdktrace.SamplingParameters{}, "helios", "macos") require.NoError(t, err) require.False(t, match) time.Sleep(time.Millisecond) } } // Validate Rules are preserved when a rule is updated with the same ruleProperties. func TestPreserveRulesWithSameRuleProperties(t *testing.T) { // getSamplingRules response to update existing manifest rule, with matching ruleProperties ruleRecords := samplingRuleRecords{ SamplingRule: &ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, } // existing rule already present in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ capacity: 100, quota: 100, quotaBalance: 80, refreshedAt: time.Unix(13000000, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: 500, sampledRequests: 10, borrowedRequests: 0, }, } clock := &mockClock{ nowTime: 1500000000, } rules := []Rule{r1} m := &Manifest{ Rules: rules, clock: clock, } // Update rules m.updateRules(&getSamplingRulesOutput{ SamplingRuleRecords: []*samplingRuleRecords{&ruleRecords}, }) require.Equal(t, r1.reservoir, m.Rules[0].reservoir) require.Equal(t, r1.samplingStatistics, m.Rules[0].samplingStatistics) } // Validate Rules are NOT preserved when a rule is updated with a different ruleProperties with the same RuleName. func TestDoNotPreserveRulesWithDifferentRuleProperties(t *testing.T) { // getSamplingRules response to update existing manifest rule, with different ruleProperties ruleRecords := samplingRuleRecords{ SamplingRule: &ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, } // existing rule already present in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10001, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ capacity: 100, quota: 100, quotaBalance: 80, refreshedAt: time.Unix(13000000, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: 500, sampledRequests: 10, borrowedRequests: 0, }, } clock := &mockClock{ nowTime: 1500000000, } rules := []Rule{r1} m := &Manifest{ Rules: rules, clock: clock, } // Update rules m.updateRules(&getSamplingRulesOutput{ SamplingRuleRecords: []*samplingRuleRecords{&ruleRecords}, }) require.Equal(t, m.Rules[0].reservoir.quota, 0.0) require.Equal(t, m.Rules[0].reservoir.quotaBalance, 0.0) require.Equal(t, *m.Rules[0].samplingStatistics, samplingStatistics{ matchedRequests: 0, sampledRequests: 0, borrowedRequests: 0, }) } // validate no data race is when capturing sampling statistics in manifest while sampling. func TestRaceUpdatingSamplingStatisticsWhenSampling(t *testing.T) { // existing rule already present in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "test", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ refreshedAt: time.Unix(15000000, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: 5, borrowedRequests: 0, sampledRequests: 0, }, } clock := &mockClock{ nowTime: 18000000, } rules := []Rule{r1} m := &Manifest{ Rules: rules, clock: clock, } // async snapshot updates go func() { for i := 0; i < 100; i++ { manifest := m.deepCopy() _, err := manifest.snapshots() require.NoError(t, err) m.mu.Lock() m.Rules = manifest.Rules m.mu.Unlock() time.Sleep(time.Millisecond) } }() // sampling logic for i := 0; i < 100; i++ { _ = r1.Sample(sdktrace.SamplingParameters{}, time.Unix(clock.nowTime+int64(i), 0)) time.Sleep(time.Millisecond) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/match.go000066400000000000000000000035511443314701600304710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "fmt" "regexp" "strings" ) // wildcardMatch returns true if text matches pattern at the given case-sensitivity; returns false otherwise. func wildcardMatch(pattern, text string) (bool, error) { patternLen := len(pattern) textLen := len(text) if patternLen == 0 { return textLen == 0, nil } if pattern == "*" { return true, nil } pattern = strings.ToLower(pattern) text = strings.ToLower(text) match, err := regexp.MatchString(toRegexPattern(pattern), text) if err != nil { return false, fmt.Errorf("wildcardMatch: unable to perform regex matching: %w", err) } return match, nil } func toRegexPattern(pattern string) string { tokenStart := -1 var result strings.Builder for i, char := range pattern { if string(char) == "*" || string(char) == "?" { if tokenStart != -1 { _, _ = result.WriteString(regexp.QuoteMeta(pattern[tokenStart:i])) tokenStart = -1 } if string(char) == "*" { _, _ = result.WriteString(".*") } else { _, _ = result.WriteString(".") } } else { if tokenStart == -1 { tokenStart = i } } } if tokenStart != -1 { _, _ = result.WriteString(regexp.QuoteMeta(pattern[tokenStart:])) } return result.String() } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/match_test.go000066400000000000000000000051341443314701600315270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal import ( "bytes" "math/rand" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // assert wildcard match is positive. func TestWildCardMatchPositive(t *testing.T) { tests := []struct { pattern string text string }{ // wildcard positive test set {"*", ""}, {"foo", "foo"}, {"foo*bar*?", "foodbaris"}, {"?o?", "foo"}, {"*oo", "foo"}, {"foo*", "foo"}, {"*o?", "foo"}, {"*", "boo"}, {"", ""}, {"a", "a"}, {"*a", "a"}, {"*a", "ba"}, {"a*", "a"}, {"a*", "ab"}, {"a*a", "aa"}, {"a*a", "aba"}, {"a*a*", "aaaaaaaaaaaaaaaaaaaaaaa"}, {"a*b*a*b*a*b*a*b*a*", "akljd9gsdfbkjhaabajkhbbyiaahkjbjhbuykjakjhabkjhbabjhkaabbabbaaakljdfsjklababkjbsdabab"}, {"a*na*ha", "anananahahanahana"}, {"***a", "a"}, {"**a**", "a"}, {"a**b", "ab"}, {"*?", "a"}, {"*??", "aa"}, {"*?", "a"}, {"*?*a*", "ba"}, {"?at", "bat"}, {"?at", "cat"}, {"?o?se", "horse"}, {"?o?se", "mouse"}, {"*s", "horse"}, {"J*", "Jeep"}, {"J*", "jeep"}, {"*/foo", "/bar/foo"}, } for _, test := range tests { match, err := wildcardMatch(test.pattern, test.text) require.NoError(t, err) assert.True(t, match, test.text) } } // assert wildcard match is negative. func TestWildCardMatchNegative(t *testing.T) { tests := []struct { pattern string text string }{ // wildcard negative test set {"", "whatever"}, {"foo", "bar"}, {"f?o", "boo"}, {"f??", "boo"}, {"fo*", "boo"}, {"f?*", "boo"}, {"abcd", "abc"}, {"??", "a"}, {"??", "a"}, {"*?*a", "a"}, } for _, test := range tests { match, err := wildcardMatch(test.pattern, test.text) require.NoError(t, err) assert.False(t, match) } } func TestLongStrings(t *testing.T) { chars := []byte{'a', 'b', 'c', 'd'} text := bytes.NewBufferString("a") for i := 0; i < 8192; i++ { _, _ = text.WriteString(string(chars[rand.Intn(len(chars))])) } _, _ = text.WriteString("b") match, err := wildcardMatch("a*b", text.String()) require.NoError(t, err) assert.True(t, match) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/reservoir.go000066400000000000000000000064321443314701600314160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "sync" "time" ) // reservoir represents a sampling statistics for a given rule and populate it's value from // the response getSamplingTargets API which sends information on sampling statistics in real-time. type reservoir struct { // Quota expiration timestamp. expiresAt time.Time // Quota assigned to client to consume per second. quota float64 // Current balance of quota. quotaBalance float64 // Total size of reservoir consumption per second. capacity float64 // Quota refresh timestamp. refreshedAt time.Time // Polling interval for quota. interval time.Duration // Stores reservoir ticks. lastTick time.Time mu sync.RWMutex } // expired returns true if current time is past expiration timestamp. Otherwise, false is returned if no quota remains. func (r *reservoir) expired(now time.Time) bool { r.mu.RLock() defer r.mu.RUnlock() return now.After(r.expiresAt) } // take consumes quota from reservoir, if any remains, then returns true. False otherwise. func (r *reservoir) take(now time.Time, borrowed bool, itemCost float64) bool { // nolint: revive // borrowed is not a control flag. r.mu.Lock() defer r.mu.Unlock() if r.capacity == 0 { return false } if r.lastTick.IsZero() { r.lastTick = now if borrowed { r.quotaBalance = 1.0 } else { r.quotaBalance = r.quota } } if r.quotaBalance >= itemCost { r.quotaBalance -= itemCost return true } // update quota balance based on elapsed time r.refreshQuotaBalanceLocked(now, borrowed) if r.quotaBalance >= itemCost { r.quotaBalance -= itemCost return true } return false } // refreshQuotaBalanceLocked refreshes the quotaBalance. If borrowed is true then add to the quota balance 1 by every second, // otherwise add to the quota balance based on assigned quota by X-Ray service. // It is assumed the lock is held when calling this. func (r *reservoir) refreshQuotaBalanceLocked(now time.Time, borrowed bool) { // nolint: revive // borrowed is not a control flag. elapsedTime := now.Sub(r.lastTick) r.lastTick = now // Calculate how much credit have we accumulated since the last tick. if borrowed { // In borrowing case since we want to enforce sample one req every second, no need to accumulate // quotaBalance based on elapsedTime when elapsedTime is greater than 1. if elapsedTime.Seconds() > 1.0 { r.quotaBalance += 1.0 } else { r.quotaBalance += elapsedTime.Seconds() } } else { totalQuotaBalanceCapacity := elapsedTime.Seconds() * r.capacity r.quotaBalance += elapsedTime.Seconds() * r.quota if r.quotaBalance > totalQuotaBalanceCapacity { r.quotaBalance = totalQuotaBalanceCapacity } } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/reservoir_test.go000066400000000000000000000150321443314701600324510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal import ( "testing" "time" "github.com/stretchr/testify/assert" ) // assert that reservoir quota is expired. func TestExpiredReservoir(t *testing.T) { clock := &mockClock{ nowTime: 1500000001, } expiresAt := time.Unix(1500000000, 0) r := &reservoir{ expiresAt: expiresAt, } expired := r.expired(clock.now()) assert.True(t, expired) } // assert that reservoir quota is still expired since now time is equal to expiresAt time. func TestExpiredReservoirSameAsClockTime(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } expiresAt := time.Unix(1500000000, 0) r := &reservoir{ expiresAt: expiresAt, } assert.False(t, r.expired(clock.now())) } // assert that borrow only 1 req/sec. func TestBorrowEverySecond(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } r := &reservoir{ capacity: 10, } s := r.take(clock.now(), true, 1.0) assert.True(t, s) s = r.take(clock.now(), true, 1.0) assert.False(t, s) // Increment clock by 1 clock = &mockClock{ nowTime: 1500000001, } s = r.take(clock.now(), true, 1.0) assert.True(t, s) } // assert that when reservoir is expired we consume from quota is 1 and then // when reservoir is not expired consume from assigned quota by X-Ray service. func TestConsumeFromBorrowConsumeFromQuota(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } r := &reservoir{ quota: 2, capacity: 10, } s := r.take(clock.now(), true, 1.0) assert.True(t, s) s = r.take(clock.now(), true, 1.0) assert.False(t, s) // Increment clock by 1 clock = &mockClock{ nowTime: 1500000001, } s = r.take(clock.now(), true, 1.0) assert.True(t, s) // Increment clock by 1 clock = &mockClock{ nowTime: 1500000002, } s = r.take(clock.now(), false, 1.0) assert.True(t, s) s = r.take(clock.now(), false, 1.0) assert.True(t, s) s = r.take(clock.now(), false, 1.0) assert.False(t, s) } // assert that we can still borrowing from reservoir is possible since assigned quota is available to consume // and it will increase used count. func TestConsumeFromReservoir(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } r := &reservoir{ quota: 2, capacity: 100, } // reservoir updates the quotaBalance for new second and allows to consume // quota balance is 0 because we are consuming from reservoir for the first time assert.Equal(t, r.quotaBalance, 0.0) assert.True(t, r.take(clock.now(), false, 1.0)) assert.Equal(t, r.quotaBalance, 1.0) assert.True(t, r.take(clock.now(), false, 1.0)) assert.Equal(t, r.quotaBalance, 0.0) // once assigned quota is consumed reservoir does not allow to consume in that second assert.False(t, r.take(clock.now(), false, 1.0)) // increase the clock by 1 clock.nowTime = 1500000001 // reservoir updates the quotaBalance for new second and allows to consume assert.Equal(t, r.quotaBalance, 0.0) assert.True(t, r.take(clock.now(), false, 1.0)) assert.Equal(t, r.quotaBalance, 1.0) assert.True(t, r.take(clock.now(), false, 1.0)) assert.Equal(t, r.quotaBalance, 0.0) // once assigned quota is consumed reservoir does not allow to consume in that second assert.False(t, r.take(clock.now(), false, 1.0)) // increase the clock by 5 clock.nowTime = 1500000005 // elapsedTime is 4 seconds so quota balance should be elapsedTime * quota = 8 and below take would consume 1 so // ultimately 7 assert.True(t, r.take(clock.now(), false, 1.0)) assert.Equal(t, r.quotaBalance, 7.0) } func TestZeroCapacityFailBorrow(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } r := &reservoir{ quota: 0, capacity: 0, } // start with no quota balance assert.Equal(t, r.quotaBalance, 0.0) // attempt to borrow from reservoir, and should fail since there is no capacity assert.False(t, r.take(clock.now(), true, 1.0)) // increase the clock by 5 clock.nowTime = 1500000005 // validate there is still no quota balance assert.Equal(t, r.quotaBalance, 0.0) // again, attempt to borrow from reservoir, and should fail since there is no capacity assert.False(t, r.take(clock.now(), true, 1.0)) } func TestResetQuotaUsageRotation(t *testing.T) { clock := &mockClock{ nowTime: 1500000000, } r := &reservoir{ quota: 5, capacity: 100, } // consume quota for second for i := 0; i < 5; i++ { assert.True(t, r.take(clock.now(), false, 1.0)) } // take() should be false since no unused quota left taken := r.take(clock.now(), false, 1.0) assert.False(t, taken) // increment epoch to reset unused quota clock = &mockClock{ nowTime: 1500000001, } // take() should be true since ununsed quota is available assert.True(t, r.take(clock.now(), false, 1.0)) } // assert that when quotaBalance exceeds totalQuotaBalanceCapacity then totalQuotaBalanceCapacity // gets assigned to quotaBalance. func TestQuotaBalanceNonBorrowExceedsCapacity(t *testing.T) { clock := &mockClock{ nowTime: 1500000001, } r := &reservoir{ quota: 6, capacity: 5, lastTick: time.Unix(1500000000, 0), } r.refreshQuotaBalanceLocked(clock.now(), false) // assert that if quotaBalance exceeds capacity then total capacity would be new quotaBalance assert.Equal(t, r.quotaBalance, r.capacity) } // assert quotaBalance and capacity of borrowing case. func TestQuotaBalanceBorrow(t *testing.T) { clock := &mockClock{ nowTime: 1500000001, } r := &reservoir{ quota: 6, capacity: 5, lastTick: time.Unix(1500000000, 0), } r.refreshQuotaBalanceLocked(clock.now(), true) // assert that if quotaBalance exceeds capacity then total capacity would be new quotaBalance assert.Equal(t, 1.0, r.quotaBalance) } // assert that when borrow is true and elapsedTime is greater than 1, then we only increase the quota balance by 1. func TestQuotaBalanceIncreaseByOneBorrowCase(t *testing.T) { clock := &mockClock{ nowTime: 1500000002, } r := &reservoir{ quota: 6, capacity: 5, quotaBalance: 0.25, lastTick: time.Unix(1500000000, 0), } r.refreshQuotaBalanceLocked(clock.now(), true) assert.Equal(t, 1.25, r.quotaBalance) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/rule.go000066400000000000000000000162311443314701600303430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/samplers/aws/xray/internal" import ( "sync/atomic" "time" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) // Rule represents a sampling rule which contains rule properties and reservoir which keeps tracks of sampling statistics of a rule. type Rule struct { samplingStatistics *samplingStatistics // reservoir has equivalent fields to store what we receive from service API getSamplingTargets. // https://docs.aws.amazon.com/xray/latest/api/API_GetSamplingTargets.html reservoir *reservoir // ruleProperty is equivalent to what we receive from service API getSamplingRules. // https://docs.aws.amazon.com/cli/latest/reference/xray/get-sampling-rules.html ruleProperties ruleProperties } type samplingStatistics struct { // matchedRequests is the number of requests matched against specific rule. matchedRequests int64 // sampledRequests is the number of requests sampled using specific rule. sampledRequests int64 // borrowedRequests is the number of requests borrowed using specific rule. borrowedRequests int64 } // stale checks if targets (sampling stats) for a given rule is expired or not. func (r *Rule) stale(now time.Time) bool { matchedRequests := atomic.LoadInt64(&r.samplingStatistics.matchedRequests) reservoirRefreshTime := r.reservoir.refreshedAt.Add(r.reservoir.interval * time.Second) return matchedRequests != 0 && now.After(reservoirRefreshTime) } // snapshot takes a snapshot of the sampling statistics counters, returning // samplingStatisticsDocument. It also resets statistics counters. func (r *Rule) snapshot(now time.Time) *samplingStatisticsDocument { name := r.ruleProperties.RuleName matchedRequests := atomic.SwapInt64(&r.samplingStatistics.matchedRequests, int64(0)) sampledRequests := atomic.SwapInt64(&r.samplingStatistics.sampledRequests, int64(0)) borrowedRequest := atomic.SwapInt64(&r.samplingStatistics.borrowedRequests, int64(0)) timeStamp := now.Unix() return &samplingStatisticsDocument{ RequestCount: &matchedRequests, SampledCount: &sampledRequests, BorrowCount: &borrowedRequest, RuleName: &name, Timestamp: &timeStamp, } } // Sample uses sampling targets of a given rule to decide // which sampling should be done and returns a SamplingResult. func (r *Rule) Sample(parameters sdktrace.SamplingParameters, now time.Time) sdktrace.SamplingResult { sd := sdktrace.SamplingResult{ Tracestate: trace.SpanContextFromContext(parameters.ParentContext).TraceState(), } atomic.AddInt64(&r.samplingStatistics.matchedRequests, int64(1)) // Fallback sampling logic if quota for a given rule is expired. if r.reservoir.expired(now) { // Borrowing one request every second. if r.reservoir.take(now, true, 1.0) { atomic.AddInt64(&r.samplingStatistics.borrowedRequests, int64(1)) sd.Decision = sdktrace.RecordAndSample return sd } // Using traceIDRatioBased sampler to sample using fixed rate. sd = sdktrace.TraceIDRatioBased(r.ruleProperties.FixedRate).ShouldSample(parameters) if sd.Decision == sdktrace.RecordAndSample { atomic.AddInt64(&r.samplingStatistics.sampledRequests, int64(1)) } return sd } // Take from reservoir quota, if quota is available for that second. if r.reservoir.take(now, false, 1.0) { atomic.AddInt64(&r.samplingStatistics.sampledRequests, int64(1)) sd.Decision = sdktrace.RecordAndSample return sd } // using traceIDRatioBased sampler to sample using fixed rate sd = sdktrace.TraceIDRatioBased(r.ruleProperties.FixedRate).ShouldSample(parameters) if sd.Decision == sdktrace.RecordAndSample { atomic.AddInt64(&r.samplingStatistics.sampledRequests, int64(1)) } return sd } // appliesTo performs a matching against rule properties to see // if a given rule does match with any of the rule set on AWS X-Ray console. func (r *Rule) appliesTo(parameters sdktrace.SamplingParameters, serviceName string, cloudPlatform string) (bool, error) { var httpTarget string var httpURL string var httpHost string var httpMethod string var HTTPURLPathMatcher bool if parameters.Attributes != nil { for _, attrs := range parameters.Attributes { if attrs.Key == "http.target" { httpTarget = attrs.Value.AsString() } if attrs.Key == "http.url" { httpURL = attrs.Value.AsString() } if attrs.Key == "http.host" { httpHost = attrs.Value.AsString() } if attrs.Key == "http.method" { httpMethod = attrs.Value.AsString() } } } // Attributes and other HTTP span attributes matching. attributeMatcher, err := r.attributeMatching(parameters) if err != nil { return attributeMatcher, err } if !attributeMatcher { return attributeMatcher, nil } serviceNameMatcher, err := wildcardMatch(r.ruleProperties.ServiceName, serviceName) if err != nil { return serviceNameMatcher, err } if !serviceNameMatcher { return serviceNameMatcher, nil } serviceTypeMatcher, err := wildcardMatch(r.ruleProperties.ServiceType, cloudPlatform) if err != nil { return serviceTypeMatcher, err } if !serviceTypeMatcher { return serviceTypeMatcher, nil } HTTPMethodMatcher, err := wildcardMatch(r.ruleProperties.HTTPMethod, httpMethod) if err != nil { return HTTPMethodMatcher, err } if !HTTPMethodMatcher { return HTTPMethodMatcher, nil } HTTPHostMatcher, err := wildcardMatch(r.ruleProperties.Host, httpHost) if err != nil { return HTTPHostMatcher, err } if !HTTPHostMatcher { return HTTPHostMatcher, nil } if httpURL != "" { HTTPURLPathMatcher, err = wildcardMatch(r.ruleProperties.URLPath, httpURL) if err != nil { return HTTPURLPathMatcher, err } if !HTTPURLPathMatcher { return HTTPURLPathMatcher, nil } } else { HTTPURLPathMatcher, err = wildcardMatch(r.ruleProperties.URLPath, httpTarget) if err != nil { return HTTPURLPathMatcher, err } if !HTTPURLPathMatcher { return HTTPURLPathMatcher, nil } } return true, nil } // attributeMatching performs a match on attributes set by users on AWS X-Ray console. func (r *Rule) attributeMatching(parameters sdktrace.SamplingParameters) (bool, error) { match := false var err error if len(r.ruleProperties.Attributes) == 0 { return true, nil } for key, value := range r.ruleProperties.Attributes { unmatchedCounter := 0 for _, attrs := range parameters.Attributes { if key == string(attrs.Key) { match, err = wildcardMatch(value, attrs.Value.AsString()) if err != nil { return false, err } if !match { return false, nil } } else { unmatchedCounter++ } } if unmatchedCounter == len(parameters.Attributes) { return false, nil } } return match, nil } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/internal/rule_test.go000066400000000000000000000410561443314701600314050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal import ( "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/trace" "github.com/stretchr/testify/assert" ) // assert that rule is active but stale due to quota is expired. func TestStaleRule(t *testing.T) { refreshedAt := time.Unix(1500000000, 0) r1 := Rule{ samplingStatistics: &samplingStatistics{ matchedRequests: 5, }, reservoir: &reservoir{ refreshedAt: refreshedAt, interval: 10, }, } now := time.Unix(1500000020, 0) s := r1.stale(now) assert.True(t, s) } // assert that rule is active and not stale. func TestFreshRule(t *testing.T) { refreshedAt := time.Unix(1500000000, 0) r1 := Rule{ samplingStatistics: &samplingStatistics{ matchedRequests: 5, }, reservoir: &reservoir{ refreshedAt: refreshedAt, interval: 10, }, } now := time.Unix(1500000009, 0) s := r1.stale(now) assert.False(t, s) } // assert that rule is inactive but not stale. func TestInactiveRule(t *testing.T) { refreshedAt := time.Unix(1500000000, 0) r1 := Rule{ samplingStatistics: &samplingStatistics{ matchedRequests: 0, }, reservoir: &reservoir{ refreshedAt: refreshedAt, interval: 10, }, } now := time.Unix(1500000011, 0) s := r1.stale(now) assert.False(t, s) } // assert on snapshot of sampling statistics counters. func TestSnapshot(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", }, samplingStatistics: &samplingStatistics{ matchedRequests: 100, sampledRequests: 12, borrowedRequests: 2, }, } now := time.Unix(1500000000, 0) ss := r1.snapshot(now) // assert counters were reset assert.Equal(t, int64(0), r1.samplingStatistics.matchedRequests) assert.Equal(t, int64(0), r1.samplingStatistics.sampledRequests) assert.Equal(t, int64(0), r1.samplingStatistics.borrowedRequests) // assert on SamplingStatistics counters assert.Equal(t, int64(100), *ss.RequestCount) assert.Equal(t, int64(12), *ss.SampledCount) assert.Equal(t, int64(2), *ss.BorrowCount) assert.Equal(t, "r1", *ss.RuleName) } // assert that reservoir is expired, borrowing 1 req during that second. func TestExpiredReservoirBorrowSample(t *testing.T) { r1 := Rule{ reservoir: &reservoir{ expiresAt: time.Unix(1500000060, 0), capacity: 10, }, ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.06, }, samplingStatistics: &samplingStatistics{}, } now := time.Unix(1500000062, 0) sd := r1.Sample(trace.SamplingParameters{}, now) assert.Equal(t, trace.RecordAndSample, sd.Decision) assert.Equal(t, int64(1), r1.samplingStatistics.borrowedRequests) assert.Equal(t, int64(0), r1.samplingStatistics.sampledRequests) assert.Equal(t, int64(1), r1.samplingStatistics.matchedRequests) } // assert that reservoir is expired, borrowed 1 req during that second so now using traceIDRatioBased sampler. func TestExpiredReservoirTraceIDRationBasedSample(t *testing.T) { r1 := Rule{ reservoir: &reservoir{ expiresAt: time.Unix(1500000060, 0), capacity: 10, lastTick: time.Unix(1500000061, 0), }, ruleProperties: ruleProperties{ RuleName: "r1", FixedRate: 0.06, }, samplingStatistics: &samplingStatistics{}, } now := time.Unix(1500000061, 0) sd := r1.Sample(trace.SamplingParameters{}, now) assert.NotEmpty(t, sd.Decision) assert.Equal(t, int64(0), r1.samplingStatistics.borrowedRequests) assert.Equal(t, int64(1), r1.samplingStatistics.sampledRequests) assert.Equal(t, int64(1), r1.samplingStatistics.matchedRequests) } // assert that reservoir is not expired, quota is available so consuming from quota. func TestConsumeFromReservoirSample(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", }, reservoir: &reservoir{ capacity: 10, quota: 10, expiresAt: time.Unix(1500000060, 0), }, samplingStatistics: &samplingStatistics{}, } now := time.Unix(1500000000, 0) sd := r1.Sample(trace.SamplingParameters{}, now) assert.Equal(t, trace.RecordAndSample, sd.Decision) assert.Equal(t, int64(1), r1.samplingStatistics.sampledRequests) assert.Equal(t, int64(0), r1.samplingStatistics.borrowedRequests) assert.Equal(t, int64(1), r1.samplingStatistics.matchedRequests) } // assert that sampling using traceIDRationBasedSampler when reservoir quota is consumed. func TestTraceIDRatioBasedSamplerReservoirIsConsumedSample(t *testing.T) { r1 := Rule{ reservoir: &reservoir{ quota: 10, expiresAt: time.Unix(1500000060, 0), lastTick: time.Unix(1500000000, 0), }, ruleProperties: ruleProperties{ FixedRate: 0.05, RuleName: "r1", }, samplingStatistics: &samplingStatistics{}, } now := time.Unix(1500000000, 0) sd := r1.Sample(trace.SamplingParameters{}, now) assert.NotEmpty(t, sd.Decision) assert.Equal(t, int64(1), r1.samplingStatistics.sampledRequests) assert.Equal(t, int64(0), r1.samplingStatistics.borrowedRequests) assert.Equal(t, int64(1), r1.samplingStatistics.matchedRequests) } // assert that when fixed rate is 0 traceIDRatioBased sampler will not sample the trace. func TestTraceIDRatioBasedSamplerFixedRateZero(t *testing.T) { r1 := Rule{ reservoir: &reservoir{ quota: 10, expiresAt: time.Unix(1500000060, 0), lastTick: time.Unix(1500000000, 0), }, ruleProperties: ruleProperties{ FixedRate: 0, RuleName: "r1", }, samplingStatistics: &samplingStatistics{}, } now := time.Unix(1500000000, 0) sd := r1.Sample(trace.SamplingParameters{}, now) assert.Equal(t, sd.Decision, trace.Drop) } func TestAppliesToMatchingWithAllAttrs(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "localhost", HTTPMethod: "GET", URLPath: "http://127.0.0.1:2000", }, } httpAttrs := []attribute.KeyValue{ attribute.String("http.host", "localhost"), attribute.String("http.method", "GET"), attribute.String("http.url", "http://127.0.0.1:2000"), } match, err := r1.appliesTo(trace.SamplingParameters{Attributes: httpAttrs}, "test-service", "EC2") require.NoError(t, err) assert.True(t, match) } // assert that matching will happen when rules has all the HTTP attrs set as '*' and // span has any attribute values. func TestAppliesToMatchingWithStarHTTPAttrs(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "*", HTTPMethod: "*", URLPath: "*", }, } httpAttrs := []attribute.KeyValue{ attribute.String("http.host", "localhost"), attribute.String("http.method", "GET"), attribute.String("http.url", "http://127.0.0.1:2000"), } match, err := r1.appliesTo(trace.SamplingParameters{Attributes: httpAttrs}, "test-service", "EC2") require.NoError(t, err) assert.True(t, match) } // assert that matching will not happen when rules has all the HTTP attrs set as non '*' values and // span has no HTTP attributes. func TestAppliesToMatchingWithHTTPAttrsNoSpanAttrs(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "localhost", HTTPMethod: "GET", URLPath: "http://127.0.0.1:2000", }, } match, err := r1.appliesTo(trace.SamplingParameters{}, "test-service", "EC2") require.NoError(t, err) assert.False(t, match) } // assert that matching will happen when rules has all the HTTP attrs set as '*' values and // span has no HTTP attributes. func TestAppliesToMatchingWithStarHTTPAttrsNoSpanAttrs(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "*", HTTPMethod: "*", URLPath: "*", }, } match, err := r1.appliesTo(trace.SamplingParameters{}, "test-service", "EC2") require.NoError(t, err) assert.True(t, match) } // assert that matching will not happen when rules has some HTTP attrs set as non '*' values and // span has no HTTP attributes. func TestAppliesToMatchingWithPartialHTTPAttrsNoSpanAttrs(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "*", HTTPMethod: "GET", URLPath: "*", }, } match, err := r1.appliesTo(trace.SamplingParameters{}, "test-service", "EC2") require.NoError(t, err) assert.False(t, match) } // assert that matching will not happen when rule and span ServiceType attr value is different. func TestAppliesToNoMatching(t *testing.T) { r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "EC2", Host: "*", HTTPMethod: "*", URLPath: "*", }, } match, err := r1.appliesTo(trace.SamplingParameters{}, "test-service", "ECS") require.NoError(t, err) assert.False(t, match) } // assert that when attribute has http.url is empty, uses http.target wildcard matching. func TestAppliesToHTTPTargetMatching(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("http.target", "target"), } r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "ECS", Host: "*", HTTPMethod: "*", URLPath: "*", }, } match, err := r1.appliesTo(trace.SamplingParameters{Attributes: commonLabels}, "test-service", "ECS") require.NoError(t, err) assert.True(t, match) } // assert early exit when rule properties retrieved from AWS X-Ray console does not match with span attributes. func TestAppliesToExitEarlyNoMatch(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelC", "fudge"), } noServiceNameMatch := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "local", ServiceType: "*", Host: "*", HTTPMethod: "*", URLPath: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelC": "fudge", }, }, } noServiceTypeMatch := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "*", ServiceType: "ECS", Host: "*", HTTPMethod: "*", URLPath: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelC": "fudge", }, }, } noHTTPMethodMatcher := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "*", ServiceType: "*", Host: "*", HTTPMethod: "GET", URLPath: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelC": "fudge", }, }, } noHTTPHostMatcher := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "*", ServiceType: "*", Host: "http://localhost:2022", HTTPMethod: "*", URLPath: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelC": "fudge", }, }, } noHTTPURLPathMatcher := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "*", ServiceType: "*", Host: "*", HTTPMethod: "*", URLPath: "/test/path", Attributes: map[string]string{}, }, } noAttributeMatcher := &Rule{ ruleProperties: ruleProperties{ RuleName: "r1", ServiceName: "test-service", ServiceType: "*", Host: "*", HTTPMethod: "*", URLPath: "*", Attributes: map[string]string{ "labelA": "chocolate", "labelC": "vanilla", }, }, } tests := []struct { rules *Rule }{ {noServiceNameMatch}, {noServiceTypeMatch}, {noHTTPMethodMatcher}, {noHTTPHostMatcher}, {noHTTPURLPathMatcher}, {noAttributeMatcher}, } for _, test := range tests { match, err := test.rules.appliesTo(trace.SamplingParameters{Attributes: commonLabels}, "test-service", "local") require.NoError(t, err) require.False(t, match) } } // assert that if rules has attribute and span has those attribute with same value then matching will happen. func TestAttributeMatching(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ Attributes: map[string]string{ "labelA": "chocolate", "labelB": "raspberry", }, }, } match, err := r1.attributeMatching(trace.SamplingParameters{Attributes: commonLabels}) require.NoError(t, err) assert.True(t, match) } // assert that if rules has no attributes then matching will happen. func TestAttributeMatchingNoRuleAttrs(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ Attributes: map[string]string{}, }, } match, err := r1.attributeMatching(trace.SamplingParameters{Attributes: commonLabels}) require.NoError(t, err) assert.True(t, match) } // assert that wildcard attributes will match. func TestAttributeWildCardMatching(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ Attributes: map[string]string{ "labelA": "choco*", "labelB": "rasp*", }, }, } match, err := r1.attributeMatching(trace.SamplingParameters{Attributes: commonLabels}) require.NoError(t, err) assert.True(t, match) } // assert that if some of the rules attributes are not present in span attributes then matching // will not happen. func TestMatchAgainstManifestRulesNoAttributeMatch(t *testing.T) { commonLabels := []attribute.KeyValue{ attribute.String("labelA", "chocolate"), attribute.String("labelB", "raspberry"), } r1 := Rule{ ruleProperties: ruleProperties{ Attributes: map[string]string{ "labelA": "chocolate", "labelC": "fudge", }, }, } match, err := r1.attributeMatching(trace.SamplingParameters{Attributes: commonLabels}) require.NoError(t, err) assert.False(t, match) } // validate no data race is happening when updating rule properties and rule targets in manifest while sampling. func TestRaceUpdatingRulesAndTargetsWhileSampling(t *testing.T) { // getSamplingRules response to update existing manifest rule ruleRecords := samplingRuleRecords{ SamplingRule: &ruleProperties{ RuleName: "r1", Priority: 10000, Host: "localhost", HTTPMethod: "*", URLPath: "/test/path", ReservoirSize: 40, FixedRate: 0.9, Version: 1, ServiceName: "helios", ResourceARN: "*", ServiceType: "*", }, } // sampling target document to update existing manifest rule rate := 0.05 quota := float64(10) ttl := float64(18000000) name := "r1" st := samplingTargetDocument{ FixedRate: &rate, ReservoirQuota: "a, ReservoirQuotaTTL: &ttl, RuleName: &name, } // existing rule already present in manifest r1 := Rule{ ruleProperties: ruleProperties{ RuleName: "r1", Priority: 10000, Host: "*", HTTPMethod: "*", URLPath: "*", ReservoirSize: 60, FixedRate: 0.5, Version: 1, ServiceName: "test", ResourceARN: "*", ServiceType: "*", }, reservoir: &reservoir{ refreshedAt: time.Unix(18000000, 0), }, samplingStatistics: &samplingStatistics{ matchedRequests: 0, borrowedRequests: 0, sampledRequests: 0, }, } clock := &mockClock{ nowTime: 1500000000, } rules := []Rule{r1} m := &Manifest{ Rules: rules, clock: clock, } // async rule updates go func() { for i := 0; i < 100; i++ { m.updateRules(&getSamplingRulesOutput{ SamplingRuleRecords: []*samplingRuleRecords{&ruleRecords}, }) time.Sleep(time.Millisecond) } }() // async target updates go func() { for i := 0; i < 100; i++ { manifest := m.deepCopy() err := manifest.updateReservoir(&st) require.NoError(t, err) time.Sleep(time.Millisecond) m.mu.Lock() m.Rules = manifest.Rules m.mu.Unlock() } }() // sampling logic for i := 0; i < 100; i++ { _ = r1.Sample(trace.SamplingParameters{}, time.Unix(clock.nowTime+int64(i), 0)) time.Sleep(time.Millisecond) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/rand.go000066400000000000000000000021331443314701600265000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" import ( crand "crypto/rand" "encoding/binary" "math/rand" "time" ) func newSeed() int64 { var seed int64 if err := binary.Read(crand.Reader, binary.BigEndian, &seed); err != nil { // fallback to timestamp seed = time.Now().UnixNano() } return seed } var seed = newSeed() func newGlobalRand() *rand.Rand { src := rand.NewSource(seed) if src64, ok := src.(rand.Source64); ok { return rand.New(src64) } return rand.New(src) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/remote_sampler.go000066400000000000000000000143361443314701600306020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" import ( "context" "time" "go.opentelemetry.io/contrib/samplers/aws/xray/internal" sdktrace "go.opentelemetry.io/otel/sdk/trace" "github.com/go-logr/logr" ) // remoteSampler is a sampler for AWS X-Ray which polls sampling rules and sampling targets // to make a sampling decision based on rules set by users on AWS X-Ray console. type remoteSampler struct { // manifest is the list of known centralized sampling rules. manifest *internal.Manifest // pollerStarted, if true represents rule and target pollers are started. pollerStarted bool // samplingRulesPollingInterval, default is 300 seconds. samplingRulesPollingInterval time.Duration serviceName string cloudPlatform string fallbackSampler *FallbackSampler // logger for logging. logger logr.Logger } // Compile time assertion that remoteSampler implements the Sampler interface. var _ sdktrace.Sampler = (*remoteSampler)(nil) // NewRemoteSampler returns a sampler which decides to sample a given request or not // based on the sampling rules set by users on AWS X-Ray console. Sampler also periodically polls // sampling rules and sampling targets. // NOTE: ctx passed in NewRemoteSampler API is being used in background go routine. Cancellation to this context can kill the background go routine. // serviceName refers to the name of the service equivalent to the one set in the AWS X-Ray console when adding sampling rules and // cloudPlatform refers to the cloud platform the service is running on ("ec2", "ecs", "eks", "lambda", etc). // Guide on AWS X-Ray remote sampling implementation (https://aws-otel.github.io/docs/getting-started/remote-sampling#otel-remote-sampling-implementation-caveats). func NewRemoteSampler(ctx context.Context, serviceName string, cloudPlatform string, opts ...Option) (sdktrace.Sampler, error) { // Create new config based on options or set to default values. cfg, err := newConfig(opts...) if err != nil { return nil, err } // create manifest with config m, err := internal.NewManifest(cfg.endpoint, cfg.logger) if err != nil { return nil, err } remoteSampler := &remoteSampler{ manifest: m, samplingRulesPollingInterval: cfg.samplingRulesPollingInterval, fallbackSampler: NewFallbackSampler(), serviceName: serviceName, cloudPlatform: cloudPlatform, logger: cfg.logger, } remoteSampler.start(ctx) return remoteSampler, nil } // ShouldSample matches span attributes with retrieved sampling rules and returns a sampling result. // If the sampling parameters do not match or the manifest is expired then the fallback sampler is used. func (rs *remoteSampler) ShouldSample(parameters sdktrace.SamplingParameters) sdktrace.SamplingResult { if rs.manifest.Expired() { // Use fallback sampler if manifest is expired. rs.logger.V(5).Info("manifest is expired so using fallback sampling strategy") return rs.fallbackSampler.ShouldSample(parameters) } r, match, err := rs.manifest.MatchAgainstManifestRules(parameters, rs.serviceName, rs.cloudPlatform) if err != nil { rs.logger.Error(err, "rule matching error, using fallback sampler") return rs.fallbackSampler.ShouldSample(parameters) } if match { // Remote sampling based on rule match. return r.Sample(parameters, time.Now()) } // Use fallback sampler if sampling rules does not match against manifest. rs.logger.V(5).Info("span does not match rules from manifest(or it is expired), using fallback sampler") return rs.fallbackSampler.ShouldSample(parameters) } // Description returns description of the sampler being used. func (rs *remoteSampler) Description() string { return "AWSXRayRemoteSampler{remote sampling with AWS X-Ray}" } func (rs *remoteSampler) start(ctx context.Context) { if !rs.pollerStarted { rs.pollerStarted = true go rs.startPoller(ctx) } } // startPoller starts the rule and target poller in a single go routine which runs periodically // to refresh the manifest and targets. func (rs *remoteSampler) startPoller(ctx context.Context) { // jitter = 5s, default duration 300 seconds. rulesTicker := newTicker(rs.samplingRulesPollingInterval, 5*time.Second) defer rulesTicker.tick.Stop() // jitter = 100ms, default duration 10 seconds. targetTicker := newTicker(rs.manifest.SamplingTargetsPollingInterval, 100*time.Millisecond) defer targetTicker.tick.Stop() // Fetch sampling rules to kick start the remote sampling. rs.refreshManifest(ctx) for { select { case _, more := <-rulesTicker.c(): if !more { return } rs.refreshManifest(ctx) continue case _, more := <-targetTicker.c(): if !more { return } refresh := rs.refreshTargets(ctx) // If LastRuleModification time is more recent than manifest refresh time, // then we explicitly perform refreshing the manifest. if refresh { rs.refreshManifest(ctx) } continue case <-ctx.Done(): return } } } // refreshManifest refreshes the manifest retrieved via getSamplingRules API. func (rs *remoteSampler) refreshManifest(ctx context.Context) { if err := rs.manifest.RefreshManifestRules(ctx); err != nil { rs.logger.Error(err, "error occurred while refreshing sampling rules") } else { rs.logger.V(5).Info("successfully fetched sampling rules") } } // refreshTarget refreshes the sampling targets in manifest retrieved via getSamplingTargets API. func (rs *remoteSampler) refreshTargets(ctx context.Context) bool { refresh := false var err error if refresh, err = rs.manifest.RefreshManifestTargets(ctx); err != nil { rs.logger.Error(err, "error occurred while refreshing sampling rule targets") } return refresh } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/remote_sampler_config.go000066400000000000000000000054071443314701600321260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" import ( "fmt" "log" "math" "net/url" "os" "time" "github.com/go-logr/logr" "github.com/go-logr/stdr" ) const ( defaultPollingInterval = 300 ) type config struct { endpoint url.URL samplingRulesPollingInterval time.Duration logger logr.Logger } // Option sets configuration on the sampler. type Option interface { apply(*config) *config } type optionFunc func(*config) *config func (f optionFunc) apply(cfg *config) *config { return f(cfg) } // WithEndpoint sets custom proxy endpoint. // If this option is not provided the default endpoint used will be http://127.0.0.1:2000. func WithEndpoint(endpoint url.URL) Option { return optionFunc(func(cfg *config) *config { cfg.endpoint = endpoint return cfg }) } // WithSamplingRulesPollingInterval sets polling interval for sampling rules. // If this option is not provided the default samplingRulesPollingInterval used will be 300 seconds. func WithSamplingRulesPollingInterval(polingInterval time.Duration) Option { return optionFunc(func(cfg *config) *config { cfg.samplingRulesPollingInterval = polingInterval return cfg }) } // WithLogger sets custom logging for remote sampling implementation. // If this option is not provided the default logger used will be go-logr/stdr (https://github.com/go-logr/stdr). func WithLogger(l logr.Logger) Option { return optionFunc(func(cfg *config) *config { cfg.logger = l return cfg }) } func newConfig(opts ...Option) (*config, error) { defaultProxyEndpoint, err := url.Parse("http://127.0.0.1:2000") if err != nil { return nil, err } cfg := &config{ endpoint: *defaultProxyEndpoint, samplingRulesPollingInterval: defaultPollingInterval * time.Second, logger: stdr.NewWithOptions(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile), stdr.Options{LogCaller: stdr.Error}), } for _, option := range opts { option.apply(cfg) } if math.Signbit(float64(cfg.samplingRulesPollingInterval)) { return nil, fmt.Errorf("config validation error: samplingRulesPollingInterval should be positive number") } return cfg, nil } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/remote_sampler_config_test.go000066400000000000000000000072651443314701600331710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "log" "net/url" "os" "testing" "time" "github.com/stretchr/testify/require" "github.com/go-logr/logr" "github.com/go-logr/stdr" "github.com/stretchr/testify/assert" ) // assert that user provided values are tied to config. func TestNewConfig(t *testing.T) { endpoint, err := url.Parse("https://127.0.0.1:5000") require.NoError(t, err) cfg, err := newConfig(WithSamplingRulesPollingInterval(400*time.Second), WithEndpoint(*endpoint), WithLogger(logr.Logger{})) require.NoError(t, err) assert.Equal(t, cfg.samplingRulesPollingInterval, 400*time.Second) assert.Equal(t, cfg.endpoint, *endpoint) assert.Equal(t, cfg.logger, logr.Logger{}) } // assert that when user did not provide values are then config would be picked up from default values. func TestDefaultConfig(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1:2000") require.NoError(t, err) cfg, err := newConfig() require.NoError(t, err) assert.Equal(t, cfg.samplingRulesPollingInterval, 300*time.Second) assert.Equal(t, cfg.endpoint, *endpoint) assert.Equal(t, cfg.logger, stdr.NewWithOptions(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile), stdr.Options{LogCaller: stdr.Error})) } // assert when some config is provided by user then other config will be picked up from default config. func TestPartialUserProvidedConfig(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1:2000") require.NoError(t, err) cfg, err := newConfig(WithSamplingRulesPollingInterval(500 * time.Second)) require.NoError(t, err) assert.Equal(t, cfg.samplingRulesPollingInterval, 500*time.Second) assert.Equal(t, cfg.endpoint, *endpoint) assert.Equal(t, cfg.logger, stdr.NewWithOptions(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile), stdr.Options{LogCaller: stdr.Error})) } // assert that valid endpoint would not result in an error. func TestValidEndpoint(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1:2000") require.NoError(t, err) cfg, err := newConfig(WithEndpoint(*endpoint)) require.NoError(t, err) assert.Equal(t, cfg.endpoint, *endpoint) } // assert that host name with special character would not result in an error. func TestValidateHostNameWithSpecialCharacterEndpoint(t *testing.T) { endpoint, err := url.Parse("http://127.0.0.1@:2000") require.NoError(t, err) cfg, err := newConfig(WithEndpoint(*endpoint)) require.NoError(t, err) assert.Equal(t, cfg.endpoint, *endpoint) } // assert that endpoint without host name would not result in an error. func TestValidateInvalidEndpoint(t *testing.T) { endpoint, err := url.Parse("https://") require.NoError(t, err) cfg, err := newConfig(WithEndpoint(*endpoint)) require.NoError(t, err) assert.Equal(t, cfg.endpoint, *endpoint) } // assert negative sampling rules interval leads to an error. func TestValidateConfigNegativeDuration(t *testing.T) { _, err := newConfig(WithSamplingRulesPollingInterval(-300 * time.Second)) assert.Error(t, err) } // assert positive sampling rules interval. func TestValidateConfigPositiveDuration(t *testing.T) { _, err := newConfig(WithSamplingRulesPollingInterval(300 * time.Second)) assert.NoError(t, err) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/remote_sampler_test.go000066400000000000000000000016261443314701600316370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray import ( "testing" "github.com/stretchr/testify/assert" ) // TestRemoteSamplerDescription assert remote sampling description. func TestRemoteSamplerDescription(t *testing.T) { rs := &remoteSampler{} s := rs.Description() assert.Equal(t, s, "AWSXRayRemoteSampler{remote sampling with AWS X-Ray}") } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/timer.go000066400000000000000000000025411443314701600266770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" import ( "time" ) // ticker is the same as time.Ticker except that it has jitters. // A Ticker must be created with newTicker. type ticker struct { tick *time.Ticker duration time.Duration jitter time.Duration } // newTicker creates a new Ticker that will send the current time on its channel with the passed jitter. func newTicker(duration, jitter time.Duration) *ticker { t := time.NewTicker(duration - time.Duration(newGlobalRand().Int63n(int64(jitter)))) jitteredTicker := ticker{ tick: t, duration: duration, jitter: jitter, } return &jitteredTicker } // c returns a channel that receives when the ticker fires. func (j *ticker) c() <-chan time.Time { return j.tick.C } open-telemetry-opentelemetry-go-contrib-2135499/samplers/aws/xray/version.go000066400000000000000000000020021443314701600272340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package xray // import "go.opentelemetry.io/contrib/samplers/aws/xray" // Version is the current release version of the AWS XRay remote sampler. func Version() string { return "0.11.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/000077500000000000000000000000001443314701600261225ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/Makefile000066400000000000000000000005211443314701600275600ustar00rootroot00000000000000PROTOC=docker run --rm -v${PWD}:${PWD} -w${PWD} otel/build-protobuf:latest --proto_path=${PWD} PROTO_INCLUDES=-I/usr/include/github.com/gogo/protobuf .PHONY: proto-gen proto-gen: mkdir -p internal/proto-gen $(PROTOC) $(PROTO_INCLUDES) \ --gogo_out=$(PWD)/internal/proto-gen \ ${PWD}/jaeger-idl/proto/api_v2/sampling.proto open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/README.md000066400000000000000000000064121443314701600274040ustar00rootroot00000000000000# Jaeger Remote Sampler This package implements [Jaeger remote sampler](https://www.jaegertracing.io/docs/latest/sampling/#remote-sampling). Remote sampler allows defining sampling configuration for services at the backend, at the granularity of service + endpoint. When using the Jaeger backend, the sampling configuration can come from two sources: 1. A static configuration file, with the ability to hot-reload it on changes. 2. [Adaptive sampling](https://www.jaegertracing.io/docs/latest/sampling/#adaptive-sampling) where Jaeger backend automatically calculates desired sampling probabilities based on the target volume of trace data per service. ## Usage Configuration in the code: ```go jaegerRemoteSampler := jaegerremote.New( "your-service-name", jaegerremote.WithSamplingServerURL("http://{sampling_service_host_name}:5778/sampling"), jaegerremote.WithSamplingRefreshInterval(10*time.Second), jaegerremote.WithInitialSampler(trace.TraceIDRatioBased(0.5)), ) tp := trace.NewTracerProvider( trace.WithSampler(jaegerRemoteSampler), ... ) otel.SetTracerProvider(tp) ``` Sampling server: * Historically, the Jaeger Agent provided the sampling server at `http://{agent_host}:5778/sampling`. * When not running the Jaeger Agent, the sampling server is also provided by the Jaeger Collector, but at a slightly different endpoint: `http://collector_host:14268/api/sampling`. * The OpenTelemetry Collector can provide the sampling endpoint `http://{otel_collector_host}:5778/sampling` by [configuring an extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/extension/jaegerremotesampling/README.md). Notes: * At this time, the Jaeger Remote Sampler can only be configured in the code, configuration via `OTEL_TRACES_SAMPLER=jaeger_sampler` environment variable is not supported. * Service name must be passed to the constructor. It will be used by the sampler to poll the backend for the sampling strategy for this service. * Both Jaeger Agent and OpenTelemetry Collector implement the Jaeger sampling service endpoint. ## Example [example/](./example) shows how to host remote sampling strategies using the OpenTelemetry Collector. The Collector uses the Jaeger receiver to host the strategy file. Note you do not need to run Jaeger to make use of the Jaeger remote sampling protocol. However, you do need Jaeger backend if you want to utilize its adaptive sampling engine that auto-calculates remote sampling strategies. Run the OpenTelemetry Collector using docker-compose: ```shell $ docker-compose up -d ``` You can fetch the strategy file using curl: ```shell $ curl 'localhost:5778/sampling?service=foo' $ curl 'localhost:5778/sampling?service=myService' ``` Run the Go program. This program will start with an initial sampling percentage of 50% and tries to fetch the sampling strategies from the OpenTelemetry Collector. It will print the entire Jaeger remote sampler structure every 10 seconds, this allows you to observe the internal sampler. ```shell $ go run . ``` ## Update generated Jaeger code Code is generated using the .proto files from [jaeger-idl](https://github.com/jaegertracing/jaeger-idl). In case [sampling.proto](./jaeger-idl/proto/api_v2/sampling.proto) is modified these have to be regenerated. ```shell $ make proto-gen ``` open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/constants.go000066400000000000000000000021411443314701600304630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" import ( "fmt" ) const ( // defaultSamplingServerPort is the default port to fetch sampling config from, via http. defaultSamplingServerPort = 5778 ) var ( // defaultSamplingServerURL is the default url to fetch sampling config from, via http. defaultSamplingServerURL = fmt.Sprintf("http://127.0.0.1:%d/sampling", defaultSamplingServerPort) ) open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/doc.go000066400000000000000000000015001443314701600272120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package jaegerremote implements the Jaeger Remote protocol. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/000077500000000000000000000000001443314701600275555ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/docker-compose.yaml000066400000000000000000000005071443314701600333550ustar00rootroot00000000000000version: "3" services: otel-collector: image: otel/opentelemetry-collector:latest command: [ "--config=/etc/otel-collector.yaml" ] volumes: - ./otel-collector.yaml:/etc/otel-collector.yaml - ./strategies.json:/etc/strategies.json ports: - "5778:5778" # default jaeger remote sampling port open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/go.mod000066400000000000000000000014311443314701600306620ustar00rootroot00000000000000module go.opentelemetry.io/contrib/samplers/jaegerremote/example go 1.18 require ( github.com/davecgh/go-spew v1.1.1 go.opentelemetry.io/contrib/samplers/jaegerremote v0.11.0 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 ) require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/protobuf v1.30.0 // indirect ) replace go.opentelemetry.io/contrib/samplers/jaegerremote => ../ open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/go.sum000066400000000000000000000374131443314701600307200ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/main.go000066400000000000000000000031611443314701600310310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "fmt" "time" "github.com/davecgh/go-spew/spew" "go.opentelemetry.io/contrib/samplers/jaegerremote" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/sdk/trace" ) func main() { jaegerRemoteSampler := jaegerremote.New( "foo", jaegerremote.WithSamplingServerURL("http://localhost:5778"), jaegerremote.WithSamplingRefreshInterval(10*time.Second), // decrease polling interval to get quicker feedback jaegerremote.WithInitialSampler(trace.TraceIDRatioBased(0.5)), ) exporter, _ := stdouttrace.New() tp := trace.NewTracerProvider( trace.WithSampler(jaegerRemoteSampler), trace.WithSyncer(exporter), // for production usage, use trace.WithBatcher(exporter) ) otel.SetTracerProvider(tp) ticker := time.Tick(time.Second) for { <-ticker fmt.Printf("\n* Jaeger Remote Sampler %v\n\n", time.Now()) spewCfg := spew.ConfigState{ Indent: " ", DisablePointerAddresses: true, } spewCfg.Dump(jaegerRemoteSampler) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/otel-collector.yaml000066400000000000000000000004541443314701600333730ustar00rootroot00000000000000receivers: jaeger: protocols: grpc: remote_sampling: host_endpoint: "0.0.0.0:5778" # default port insecure: true strategy_file: "/etc/strategies.json" exporters: logging: service: pipelines: traces: receivers: [ jaeger ] exporters: [ logging ] open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/example/strategies.json000066400000000000000000000010311443314701600326150ustar00rootroot00000000000000{ "service_strategies": [ { "service": "foo", "type": "probabilistic", "param": 0.8, "operation_strategies": [ { "operation": "op1", "type": "probabilistic", "param": 0.2 }, { "operation": "op2", "type": "probabilistic", "param": 0.4 } ] }, { "service": "bar", "type": "ratelimiting", "param": 5 } ], "default_strategy": { "type": "probabilistic", "param": 0.2 } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/go.mod000066400000000000000000000012701443314701600272300ustar00rootroot00000000000000module go.opentelemetry.io/contrib/samplers/jaegerremote go 1.19 require ( github.com/go-logr/logr v1.2.4 github.com/gogo/protobuf v1.3.2 github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/go.sum000066400000000000000000000374661443314701600272750ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/000077500000000000000000000000001443314701600277365ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/proto-gen/000077500000000000000000000000001443314701600316505ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/proto-gen/jaeger-idl/000077500000000000000000000000001443314701600336535ustar00rootroot00000000000000proto/000077500000000000000000000000001443314701600347375ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/proto-gen/jaeger-idlapi_v2/000077500000000000000000000000001443314701600361175ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/proto-gen/jaeger-idl/protosampling.pb.go000066400000000000000000001260331443314701600406650ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: jaeger-idl/proto/api_v2/sampling.proto package api_v2 import ( encoding_binary "encoding/binary" fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "google.golang.org/genproto/googleapis/api/annotations" io "io" math "math" math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type SamplingStrategyType int32 const ( SamplingStrategyType_PROBABILISTIC SamplingStrategyType = 0 SamplingStrategyType_RATE_LIMITING SamplingStrategyType = 1 ) var SamplingStrategyType_name = map[int32]string{ 0: "PROBABILISTIC", 1: "RATE_LIMITING", } var SamplingStrategyType_value = map[string]int32{ "PROBABILISTIC": 0, "RATE_LIMITING": 1, } func (x SamplingStrategyType) String() string { return proto.EnumName(SamplingStrategyType_name, int32(x)) } func (SamplingStrategyType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{0} } type ProbabilisticSamplingStrategy struct { SamplingRate float64 `protobuf:"fixed64,1,opt,name=samplingRate,proto3" json:"samplingRate,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *ProbabilisticSamplingStrategy) Reset() { *m = ProbabilisticSamplingStrategy{} } func (m *ProbabilisticSamplingStrategy) String() string { return proto.CompactTextString(m) } func (*ProbabilisticSamplingStrategy) ProtoMessage() {} func (*ProbabilisticSamplingStrategy) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{0} } func (m *ProbabilisticSamplingStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *ProbabilisticSamplingStrategy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_ProbabilisticSamplingStrategy.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *ProbabilisticSamplingStrategy) XXX_Merge(src proto.Message) { xxx_messageInfo_ProbabilisticSamplingStrategy.Merge(m, src) } func (m *ProbabilisticSamplingStrategy) XXX_Size() int { return m.Size() } func (m *ProbabilisticSamplingStrategy) XXX_DiscardUnknown() { xxx_messageInfo_ProbabilisticSamplingStrategy.DiscardUnknown(m) } var xxx_messageInfo_ProbabilisticSamplingStrategy proto.InternalMessageInfo func (m *ProbabilisticSamplingStrategy) GetSamplingRate() float64 { if m != nil { return m.SamplingRate } return 0 } type RateLimitingSamplingStrategy struct { MaxTracesPerSecond int32 `protobuf:"varint,1,opt,name=maxTracesPerSecond,proto3" json:"maxTracesPerSecond,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *RateLimitingSamplingStrategy) Reset() { *m = RateLimitingSamplingStrategy{} } func (m *RateLimitingSamplingStrategy) String() string { return proto.CompactTextString(m) } func (*RateLimitingSamplingStrategy) ProtoMessage() {} func (*RateLimitingSamplingStrategy) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{1} } func (m *RateLimitingSamplingStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *RateLimitingSamplingStrategy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_RateLimitingSamplingStrategy.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *RateLimitingSamplingStrategy) XXX_Merge(src proto.Message) { xxx_messageInfo_RateLimitingSamplingStrategy.Merge(m, src) } func (m *RateLimitingSamplingStrategy) XXX_Size() int { return m.Size() } func (m *RateLimitingSamplingStrategy) XXX_DiscardUnknown() { xxx_messageInfo_RateLimitingSamplingStrategy.DiscardUnknown(m) } var xxx_messageInfo_RateLimitingSamplingStrategy proto.InternalMessageInfo func (m *RateLimitingSamplingStrategy) GetMaxTracesPerSecond() int32 { if m != nil { return m.MaxTracesPerSecond } return 0 } type OperationSamplingStrategy struct { Operation string `protobuf:"bytes,1,opt,name=operation,proto3" json:"operation,omitempty"` ProbabilisticSampling *ProbabilisticSamplingStrategy `protobuf:"bytes,2,opt,name=probabilisticSampling,proto3" json:"probabilisticSampling,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *OperationSamplingStrategy) Reset() { *m = OperationSamplingStrategy{} } func (m *OperationSamplingStrategy) String() string { return proto.CompactTextString(m) } func (*OperationSamplingStrategy) ProtoMessage() {} func (*OperationSamplingStrategy) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{2} } func (m *OperationSamplingStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *OperationSamplingStrategy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_OperationSamplingStrategy.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *OperationSamplingStrategy) XXX_Merge(src proto.Message) { xxx_messageInfo_OperationSamplingStrategy.Merge(m, src) } func (m *OperationSamplingStrategy) XXX_Size() int { return m.Size() } func (m *OperationSamplingStrategy) XXX_DiscardUnknown() { xxx_messageInfo_OperationSamplingStrategy.DiscardUnknown(m) } var xxx_messageInfo_OperationSamplingStrategy proto.InternalMessageInfo func (m *OperationSamplingStrategy) GetOperation() string { if m != nil { return m.Operation } return "" } func (m *OperationSamplingStrategy) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { if m != nil { return m.ProbabilisticSampling } return nil } type PerOperationSamplingStrategies struct { DefaultSamplingProbability float64 `protobuf:"fixed64,1,opt,name=defaultSamplingProbability,proto3" json:"defaultSamplingProbability,omitempty"` DefaultLowerBoundTracesPerSecond float64 `protobuf:"fixed64,2,opt,name=defaultLowerBoundTracesPerSecond,proto3" json:"defaultLowerBoundTracesPerSecond,omitempty"` PerOperationStrategies []*OperationSamplingStrategy `protobuf:"bytes,3,rep,name=perOperationStrategies,proto3" json:"perOperationStrategies,omitempty"` DefaultUpperBoundTracesPerSecond float64 `protobuf:"fixed64,4,opt,name=defaultUpperBoundTracesPerSecond,proto3" json:"defaultUpperBoundTracesPerSecond,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *PerOperationSamplingStrategies) Reset() { *m = PerOperationSamplingStrategies{} } func (m *PerOperationSamplingStrategies) String() string { return proto.CompactTextString(m) } func (*PerOperationSamplingStrategies) ProtoMessage() {} func (*PerOperationSamplingStrategies) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{3} } func (m *PerOperationSamplingStrategies) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *PerOperationSamplingStrategies) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_PerOperationSamplingStrategies.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *PerOperationSamplingStrategies) XXX_Merge(src proto.Message) { xxx_messageInfo_PerOperationSamplingStrategies.Merge(m, src) } func (m *PerOperationSamplingStrategies) XXX_Size() int { return m.Size() } func (m *PerOperationSamplingStrategies) XXX_DiscardUnknown() { xxx_messageInfo_PerOperationSamplingStrategies.DiscardUnknown(m) } var xxx_messageInfo_PerOperationSamplingStrategies proto.InternalMessageInfo func (m *PerOperationSamplingStrategies) GetDefaultSamplingProbability() float64 { if m != nil { return m.DefaultSamplingProbability } return 0 } func (m *PerOperationSamplingStrategies) GetDefaultLowerBoundTracesPerSecond() float64 { if m != nil { return m.DefaultLowerBoundTracesPerSecond } return 0 } func (m *PerOperationSamplingStrategies) GetPerOperationStrategies() []*OperationSamplingStrategy { if m != nil { return m.PerOperationStrategies } return nil } func (m *PerOperationSamplingStrategies) GetDefaultUpperBoundTracesPerSecond() float64 { if m != nil { return m.DefaultUpperBoundTracesPerSecond } return 0 } type SamplingStrategyResponse struct { StrategyType SamplingStrategyType `protobuf:"varint,1,opt,name=strategyType,proto3,enum=jaeger.api_v2.SamplingStrategyType" json:"strategyType,omitempty"` ProbabilisticSampling *ProbabilisticSamplingStrategy `protobuf:"bytes,2,opt,name=probabilisticSampling,proto3" json:"probabilisticSampling,omitempty"` RateLimitingSampling *RateLimitingSamplingStrategy `protobuf:"bytes,3,opt,name=rateLimitingSampling,proto3" json:"rateLimitingSampling,omitempty"` OperationSampling *PerOperationSamplingStrategies `protobuf:"bytes,4,opt,name=operationSampling,proto3" json:"operationSampling,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *SamplingStrategyResponse) Reset() { *m = SamplingStrategyResponse{} } func (m *SamplingStrategyResponse) String() string { return proto.CompactTextString(m) } func (*SamplingStrategyResponse) ProtoMessage() {} func (*SamplingStrategyResponse) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{4} } func (m *SamplingStrategyResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *SamplingStrategyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_SamplingStrategyResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *SamplingStrategyResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_SamplingStrategyResponse.Merge(m, src) } func (m *SamplingStrategyResponse) XXX_Size() int { return m.Size() } func (m *SamplingStrategyResponse) XXX_DiscardUnknown() { xxx_messageInfo_SamplingStrategyResponse.DiscardUnknown(m) } var xxx_messageInfo_SamplingStrategyResponse proto.InternalMessageInfo func (m *SamplingStrategyResponse) GetStrategyType() SamplingStrategyType { if m != nil { return m.StrategyType } return SamplingStrategyType_PROBABILISTIC } func (m *SamplingStrategyResponse) GetProbabilisticSampling() *ProbabilisticSamplingStrategy { if m != nil { return m.ProbabilisticSampling } return nil } func (m *SamplingStrategyResponse) GetRateLimitingSampling() *RateLimitingSamplingStrategy { if m != nil { return m.RateLimitingSampling } return nil } func (m *SamplingStrategyResponse) GetOperationSampling() *PerOperationSamplingStrategies { if m != nil { return m.OperationSampling } return nil } type SamplingStrategyParameters struct { ServiceName string `protobuf:"bytes,1,opt,name=serviceName,proto3" json:"serviceName,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *SamplingStrategyParameters) Reset() { *m = SamplingStrategyParameters{} } func (m *SamplingStrategyParameters) String() string { return proto.CompactTextString(m) } func (*SamplingStrategyParameters) ProtoMessage() {} func (*SamplingStrategyParameters) Descriptor() ([]byte, []int) { return fileDescriptor_ae32d90db01957f7, []int{5} } func (m *SamplingStrategyParameters) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } func (m *SamplingStrategyParameters) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { return xxx_messageInfo_SamplingStrategyParameters.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { return nil, err } return b[:n], nil } } func (m *SamplingStrategyParameters) XXX_Merge(src proto.Message) { xxx_messageInfo_SamplingStrategyParameters.Merge(m, src) } func (m *SamplingStrategyParameters) XXX_Size() int { return m.Size() } func (m *SamplingStrategyParameters) XXX_DiscardUnknown() { xxx_messageInfo_SamplingStrategyParameters.DiscardUnknown(m) } var xxx_messageInfo_SamplingStrategyParameters proto.InternalMessageInfo func (m *SamplingStrategyParameters) GetServiceName() string { if m != nil { return m.ServiceName } return "" } func init() { proto.RegisterEnum("jaeger.api_v2.SamplingStrategyType", SamplingStrategyType_name, SamplingStrategyType_value) proto.RegisterType((*ProbabilisticSamplingStrategy)(nil), "jaeger.api_v2.ProbabilisticSamplingStrategy") proto.RegisterType((*RateLimitingSamplingStrategy)(nil), "jaeger.api_v2.RateLimitingSamplingStrategy") proto.RegisterType((*OperationSamplingStrategy)(nil), "jaeger.api_v2.OperationSamplingStrategy") proto.RegisterType((*PerOperationSamplingStrategies)(nil), "jaeger.api_v2.PerOperationSamplingStrategies") proto.RegisterType((*SamplingStrategyResponse)(nil), "jaeger.api_v2.SamplingStrategyResponse") proto.RegisterType((*SamplingStrategyParameters)(nil), "jaeger.api_v2.SamplingStrategyParameters") } func init() { proto.RegisterFile("jaeger-idl/proto/api_v2/sampling.proto", fileDescriptor_ae32d90db01957f7) } var fileDescriptor_ae32d90db01957f7 = []byte{ // 577 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0xcf, 0x6f, 0x12, 0x41, 0x14, 0x76, 0x40, 0x9b, 0xf4, 0xd1, 0x6a, 0x3b, 0x56, 0x5d, 0x09, 0x25, 0x64, 0x9b, 0x28, 0x56, 0x81, 0x64, 0xbd, 0x19, 0xd3, 0xa4, 0x34, 0x86, 0xac, 0xa1, 0x94, 0x2c, 0x78, 0xd1, 0x03, 0x0e, 0xf0, 0xdc, 0x8c, 0x81, 0x9d, 0xcd, 0xec, 0xb4, 0xca, 0xd5, 0xc4, 0xab, 0x17, 0xcf, 0x5e, 0xfc, 0x6b, 0x3c, 0x9a, 0x78, 0xf3, 0x64, 0x88, 0x7f, 0x88, 0xd9, 0x5f, 0x2d, 0x2c, 0x0b, 0xdc, 0x3c, 0xed, 0xe6, 0xbd, 0x6f, 0xbe, 0xef, 0x7b, 0x6f, 0xde, 0x3c, 0x78, 0xf0, 0x9e, 0xa1, 0x8d, 0xb2, 0xc2, 0x87, 0xa3, 0x9a, 0x2b, 0x85, 0x12, 0x35, 0xe6, 0xf2, 0xde, 0x85, 0x51, 0xf3, 0xd8, 0xd8, 0x1d, 0x71, 0xc7, 0xae, 0x06, 0x51, 0xba, 0x1d, 0xe2, 0xaa, 0x61, 0x36, 0xbf, 0x67, 0x0b, 0x5b, 0x84, 0x78, 0xff, 0x2f, 0x04, 0xe5, 0x0b, 0xb6, 0x10, 0xf6, 0x08, 0x7d, 0x8a, 0x1a, 0x73, 0x1c, 0xa1, 0x98, 0xe2, 0xc2, 0xf1, 0xc2, 0xac, 0x7e, 0x02, 0xfb, 0x6d, 0x29, 0xfa, 0xac, 0xcf, 0x47, 0xdc, 0x53, 0x7c, 0xd0, 0x89, 0x14, 0x3a, 0x4a, 0x32, 0x85, 0xf6, 0x84, 0xea, 0xb0, 0x15, 0xab, 0x5a, 0x4c, 0xa1, 0x46, 0x4a, 0xa4, 0x4c, 0xac, 0xb9, 0x98, 0xde, 0x82, 0x82, 0xff, 0x6d, 0xf2, 0x31, 0x57, 0xfe, 0xd9, 0x24, 0x47, 0x15, 0xe8, 0x98, 0x7d, 0xec, 0x4a, 0x36, 0x40, 0xaf, 0x8d, 0xb2, 0x83, 0x03, 0xe1, 0x0c, 0x03, 0xa6, 0x1b, 0x56, 0x4a, 0x46, 0xff, 0x46, 0xe0, 0xfe, 0x99, 0x8b, 0x32, 0x70, 0xba, 0xc0, 0x56, 0x80, 0x4d, 0x11, 0x27, 0x03, 0x92, 0x4d, 0xeb, 0x2a, 0x40, 0xfb, 0x70, 0xc7, 0x4d, 0x2b, 0x48, 0xcb, 0x94, 0x48, 0x39, 0x67, 0x3c, 0xa9, 0xce, 0xf5, 0xac, 0xba, 0xb2, 0x78, 0x2b, 0x9d, 0x4a, 0xff, 0x9d, 0x81, 0x62, 0x1b, 0xe5, 0x32, 0x8b, 0x1c, 0x3d, 0x7a, 0x04, 0xf9, 0x21, 0xbe, 0x63, 0xe7, 0x23, 0x15, 0x27, 0x2f, 0x95, 0xd4, 0x24, 0x6a, 0xe2, 0x0a, 0x04, 0x7d, 0x09, 0xa5, 0x28, 0xdb, 0x14, 0x1f, 0x50, 0xd6, 0xc5, 0xb9, 0x33, 0x4c, 0x36, 0x30, 0x13, 0xb0, 0xac, 0xc5, 0xd1, 0xb7, 0x70, 0xd7, 0x9d, 0x75, 0x7b, 0xe9, 0x52, 0xcb, 0x96, 0xb2, 0xe5, 0x9c, 0x51, 0x4e, 0xf4, 0x64, 0x69, 0xeb, 0xad, 0x25, 0x3c, 0x33, 0x6e, 0x5f, 0xb9, 0xee, 0x12, 0xb7, 0xd7, 0xe7, 0xdc, 0x2e, 0xc5, 0xe9, 0x9f, 0xb3, 0xa0, 0x2d, 0x08, 0xa3, 0xe7, 0x0a, 0xc7, 0x43, 0xda, 0x80, 0x2d, 0x2f, 0x8a, 0x75, 0x27, 0x6e, 0x38, 0x8d, 0x37, 0x8d, 0x83, 0x44, 0x01, 0xc9, 0xe3, 0x3e, 0xd4, 0x9a, 0x3b, 0xf8, 0x3f, 0xc6, 0x84, 0xf6, 0x60, 0x4f, 0xa6, 0x3c, 0x0b, 0x2d, 0x1b, 0x48, 0x3c, 0x4e, 0x48, 0xac, 0x7a, 0x41, 0x56, 0x2a, 0x11, 0x7d, 0x03, 0xbb, 0x22, 0x79, 0x57, 0x41, 0x9f, 0x73, 0x46, 0x25, 0x59, 0xc0, 0xca, 0x71, 0xb5, 0x16, 0x79, 0xf4, 0x23, 0xc8, 0x27, 0x6d, 0xb4, 0x99, 0x64, 0x63, 0x54, 0x28, 0x3d, 0x5a, 0x82, 0x9c, 0x87, 0xf2, 0x82, 0x0f, 0xb0, 0xc5, 0xc6, 0x18, 0x3d, 0xc3, 0xd9, 0xd0, 0xe1, 0x73, 0xd8, 0x4b, 0xbb, 0x07, 0xba, 0x0b, 0xdb, 0x6d, 0xeb, 0xac, 0x7e, 0x5c, 0x37, 0x9b, 0x66, 0xa7, 0x6b, 0x9e, 0xec, 0x5c, 0xf3, 0x43, 0xd6, 0x71, 0xf7, 0x45, 0xaf, 0x69, 0x9e, 0x9a, 0x5d, 0xb3, 0xd5, 0xd8, 0x21, 0xc6, 0x77, 0x02, 0xb7, 0xe2, 0xe3, 0xa7, 0xcc, 0x61, 0x36, 0x4a, 0xfa, 0x85, 0xc0, 0xed, 0x06, 0xaa, 0x85, 0x85, 0xf0, 0x68, 0xcd, 0xf5, 0x5f, 0xd9, 0xce, 0x3f, 0x5c, 0x03, 0x8d, 0x07, 0x4d, 0x3f, 0xf8, 0xf4, 0xeb, 0xef, 0xd7, 0xcc, 0xbe, 0xae, 0x05, 0x7b, 0x73, 0x66, 0xf5, 0xc6, 0xc8, 0x67, 0xe4, 0xb0, 0x5e, 0xf9, 0x31, 0x2d, 0x92, 0x9f, 0xd3, 0x22, 0xf9, 0x33, 0x2d, 0x12, 0xb8, 0xc7, 0x45, 0xc4, 0xae, 0x24, 0x1b, 0xf8, 0x5b, 0x3a, 0x14, 0x79, 0xbd, 0x11, 0x7e, 0xfb, 0x1b, 0xc1, 0xca, 0x7d, 0xfa, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x60, 0xd2, 0xcd, 0xa7, 0xdf, 0x05, 0x00, 0x00, } func (m *ProbabilisticSamplingStrategy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *ProbabilisticSamplingStrategy) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *ProbabilisticSamplingStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.SamplingRate != 0 { i -= 8 encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.SamplingRate)))) i-- dAtA[i] = 0x9 } return len(dAtA) - i, nil } func (m *RateLimitingSamplingStrategy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *RateLimitingSamplingStrategy) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *RateLimitingSamplingStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.MaxTracesPerSecond != 0 { i = encodeVarintSampling(dAtA, i, uint64(m.MaxTracesPerSecond)) i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil } func (m *OperationSamplingStrategy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *OperationSamplingStrategy) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *OperationSamplingStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.ProbabilisticSampling != nil { { size, err := m.ProbabilisticSampling.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintSampling(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 } if len(m.Operation) > 0 { i -= len(m.Operation) copy(dAtA[i:], m.Operation) i = encodeVarintSampling(dAtA, i, uint64(len(m.Operation))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } func (m *PerOperationSamplingStrategies) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *PerOperationSamplingStrategies) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *PerOperationSamplingStrategies) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.DefaultUpperBoundTracesPerSecond != 0 { i -= 8 encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.DefaultUpperBoundTracesPerSecond)))) i-- dAtA[i] = 0x21 } if len(m.PerOperationStrategies) > 0 { for iNdEx := len(m.PerOperationStrategies) - 1; iNdEx >= 0; iNdEx-- { { size, err := m.PerOperationStrategies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintSampling(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a } } if m.DefaultLowerBoundTracesPerSecond != 0 { i -= 8 encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.DefaultLowerBoundTracesPerSecond)))) i-- dAtA[i] = 0x11 } if m.DefaultSamplingProbability != 0 { i -= 8 encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.DefaultSamplingProbability)))) i-- dAtA[i] = 0x9 } return len(dAtA) - i, nil } func (m *SamplingStrategyResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *SamplingStrategyResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *SamplingStrategyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if m.OperationSampling != nil { { size, err := m.OperationSampling.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintSampling(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x22 } if m.RateLimitingSampling != nil { { size, err := m.RateLimitingSampling.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintSampling(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x1a } if m.ProbabilisticSampling != nil { { size, err := m.ProbabilisticSampling.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } i -= size i = encodeVarintSampling(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x12 } if m.StrategyType != 0 { i = encodeVarintSampling(dAtA, i, uint64(m.StrategyType)) i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil } func (m *SamplingStrategyParameters) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } func (m *SamplingStrategyParameters) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *SamplingStrategyParameters) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l if m.XXX_unrecognized != nil { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ServiceName) > 0 { i -= len(m.ServiceName) copy(dAtA[i:], m.ServiceName) i = encodeVarintSampling(dAtA, i, uint64(len(m.ServiceName))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } func encodeVarintSampling(dAtA []byte, offset int, v uint64) int { offset -= sovSampling(v) base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) return base } func (m *ProbabilisticSamplingStrategy) Size() (n int) { if m == nil { return 0 } var l int _ = l if m.SamplingRate != 0 { n += 9 } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *RateLimitingSamplingStrategy) Size() (n int) { if m == nil { return 0 } var l int _ = l if m.MaxTracesPerSecond != 0 { n += 1 + sovSampling(uint64(m.MaxTracesPerSecond)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *OperationSamplingStrategy) Size() (n int) { if m == nil { return 0 } var l int _ = l l = len(m.Operation) if l > 0 { n += 1 + l + sovSampling(uint64(l)) } if m.ProbabilisticSampling != nil { l = m.ProbabilisticSampling.Size() n += 1 + l + sovSampling(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *PerOperationSamplingStrategies) Size() (n int) { if m == nil { return 0 } var l int _ = l if m.DefaultSamplingProbability != 0 { n += 9 } if m.DefaultLowerBoundTracesPerSecond != 0 { n += 9 } if len(m.PerOperationStrategies) > 0 { for _, e := range m.PerOperationStrategies { l = e.Size() n += 1 + l + sovSampling(uint64(l)) } } if m.DefaultUpperBoundTracesPerSecond != 0 { n += 9 } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *SamplingStrategyResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l if m.StrategyType != 0 { n += 1 + sovSampling(uint64(m.StrategyType)) } if m.ProbabilisticSampling != nil { l = m.ProbabilisticSampling.Size() n += 1 + l + sovSampling(uint64(l)) } if m.RateLimitingSampling != nil { l = m.RateLimitingSampling.Size() n += 1 + l + sovSampling(uint64(l)) } if m.OperationSampling != nil { l = m.OperationSampling.Size() n += 1 + l + sovSampling(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func (m *SamplingStrategyParameters) Size() (n int) { if m == nil { return 0 } var l int _ = l l = len(m.ServiceName) if l > 0 { n += 1 + l + sovSampling(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } func sovSampling(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } func sozSampling(x uint64) (n int) { return sovSampling(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (m *ProbabilisticSamplingStrategy) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: ProbabilisticSamplingStrategy: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: ProbabilisticSamplingStrategy: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field SamplingRate", wireType) } var v uint64 if (iNdEx + 8) > l { return io.ErrUnexpectedEOF } v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 m.SamplingRate = float64(math.Float64frombits(v)) default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *RateLimitingSamplingStrategy) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: RateLimitingSamplingStrategy: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: RateLimitingSamplingStrategy: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field MaxTracesPerSecond", wireType) } m.MaxTracesPerSecond = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ m.MaxTracesPerSecond |= int32(b&0x7F) << shift if b < 0x80 { break } } default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *OperationSamplingStrategy) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: OperationSamplingStrategy: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: OperationSamplingStrategy: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } m.Operation = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProbabilisticSampling", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } if m.ProbabilisticSampling == nil { m.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} } if err := m.ProbabilisticSampling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *PerOperationSamplingStrategies) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: PerOperationSamplingStrategies: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: PerOperationSamplingStrategies: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field DefaultSamplingProbability", wireType) } var v uint64 if (iNdEx + 8) > l { return io.ErrUnexpectedEOF } v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 m.DefaultSamplingProbability = float64(math.Float64frombits(v)) case 2: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field DefaultLowerBoundTracesPerSecond", wireType) } var v uint64 if (iNdEx + 8) > l { return io.ErrUnexpectedEOF } v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 m.DefaultLowerBoundTracesPerSecond = float64(math.Float64frombits(v)) case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PerOperationStrategies", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } m.PerOperationStrategies = append(m.PerOperationStrategies, &OperationSamplingStrategy{}) if err := m.PerOperationStrategies[len(m.PerOperationStrategies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 4: if wireType != 1 { return fmt.Errorf("proto: wrong wireType = %d for field DefaultUpperBoundTracesPerSecond", wireType) } var v uint64 if (iNdEx + 8) > l { return io.ErrUnexpectedEOF } v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 m.DefaultUpperBoundTracesPerSecond = float64(math.Float64frombits(v)) default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *SamplingStrategyResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: SamplingStrategyResponse: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: SamplingStrategyResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field StrategyType", wireType) } m.StrategyType = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ m.StrategyType |= SamplingStrategyType(b&0x7F) << shift if b < 0x80 { break } } case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProbabilisticSampling", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } if m.ProbabilisticSampling == nil { m.ProbabilisticSampling = &ProbabilisticSamplingStrategy{} } if err := m.ProbabilisticSampling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RateLimitingSampling", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } if m.RateLimitingSampling == nil { m.RateLimitingSampling = &RateLimitingSamplingStrategy{} } if err := m.RateLimitingSampling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field OperationSampling", wireType) } var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { break } } if msglen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } if m.OperationSampling == nil { m.OperationSampling = &PerOperationSamplingStrategies{} } if err := m.OperationSampling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func (m *SamplingStrategyParameters) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= uint64(b&0x7F) << shift if b < 0x80 { break } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { return fmt.Errorf("proto: SamplingStrategyParameters: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: SamplingStrategyParameters: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ServiceName", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSampling } if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } intStringLen := int(stringLen) if intStringLen < 0 { return ErrInvalidLengthSampling } postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthSampling } if postIndex > l { return io.ErrUnexpectedEOF } m.ServiceName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSampling(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSampling } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } if iNdEx > l { return io.ErrUnexpectedEOF } return nil } func skipSampling(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowSampling } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } } wireType := int(wire & 0x7) switch wireType { case 0: for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowSampling } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } iNdEx++ if dAtA[iNdEx-1] < 0x80 { break } } case 1: iNdEx += 8 case 2: var length int for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowSampling } if iNdEx >= l { return 0, io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ length |= (int(b) & 0x7F) << shift if b < 0x80 { break } } if length < 0 { return 0, ErrInvalidLengthSampling } iNdEx += length case 3: depth++ case 4: if depth == 0 { return 0, ErrUnexpectedEndOfGroupSampling } depth-- case 5: iNdEx += 4 default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } if iNdEx < 0 { return 0, ErrInvalidLengthSampling } if depth == 0 { return iNdEx, nil } } return 0, io.ErrUnexpectedEOF } var ( ErrInvalidLengthSampling = fmt.Errorf("proto: negative length found during unmarshaling") ErrIntOverflowSampling = fmt.Errorf("proto: integer overflow") ErrUnexpectedEndOfGroupSampling = fmt.Errorf("proto: unexpected end of group") ) open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/testutils/000077500000000000000000000000001443314701600317765ustar00rootroot00000000000000mock_agent.go000066400000000000000000000053651443314701600343660ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/testutils// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testutils // import "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/testutils" import ( "encoding/json" "fmt" "net/http" "net/http/httptest" ) // StartMockAgent runs a mock representation of jaeger-agent. // This function returns a started server. func StartMockAgent() (*MockAgent, error) { samplingManager := newSamplingManager() samplingHandler := &samplingHandler{manager: samplingManager} samplingServer := httptest.NewServer(samplingHandler) agent := &MockAgent{ samplingMgr: samplingManager, samplingSrv: samplingServer, } return agent, nil } // Close stops the serving of traffic. func (s *MockAgent) Close() { s.samplingSrv.Close() } // MockAgent is a mock representation of Jaeger Agent. // It has an HTTP endpoint for sampling strategies. type MockAgent struct { samplingMgr *samplingManager samplingSrv *httptest.Server } // SamplingServerAddr returns the host:port of HTTP server exposing sampling strategy endpoint. func (s *MockAgent) SamplingServerAddr() string { return s.samplingSrv.Listener.Addr().String() } // AddSamplingStrategy registers a sampling strategy for a service. func (s *MockAgent) AddSamplingStrategy(service string, strategy interface{}) { s.samplingMgr.AddSamplingStrategy(service, strategy) } type samplingHandler struct { manager *samplingManager } func (h *samplingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { services := r.URL.Query()["service"] if len(services) == 0 { http.Error(w, "'service' parameter is empty", http.StatusBadRequest) return } if len(services) > 1 { http.Error(w, "'service' parameter must occur only once", http.StatusBadRequest) return } resp, err := h.manager.GetSamplingStrategy(services[0]) if err != nil { http.Error(w, fmt.Sprintf("Error retrieving strategy: %+v", err), http.StatusInternalServerError) return } data, err := json.Marshal(resp) if err != nil { http.Error(w, "Cannot marshall Thrift to JSON", http.StatusInternalServerError) return } w.Header().Add("Content-Type", "application/json") if _, err := w.Write(data); err != nil { return } } mock_agent_test.go000066400000000000000000000042651443314701600354230ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/testutils// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testutils import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/utils" ) func TestMockAgentSamplingManager(t *testing.T) { mockAgent, err := StartMockAgent() require.NoError(t, err) defer mockAgent.Close() err = utils.GetJSON("http://"+mockAgent.SamplingServerAddr()+"/", nil) require.Error(t, err, "no 'service' parameter") err = utils.GetJSON("http://"+mockAgent.SamplingServerAddr()+"/?service=a&service=b", nil) require.Error(t, err, "Too many 'service' parameters") var resp jaeger_api_v2.SamplingStrategyResponse err = utils.GetJSON("http://"+mockAgent.SamplingServerAddr()+"/?service=something", &resp) require.NoError(t, err) assert.Equal(t, jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, resp.StrategyType) mockAgent.AddSamplingStrategy("service123", &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, RateLimitingSampling: &jaeger_api_v2.RateLimitingSamplingStrategy{ MaxTracesPerSecond: 123, }, }) err = utils.GetJSON("http://"+mockAgent.SamplingServerAddr()+"/?service=service123", &resp) require.NoError(t, err) assert.Equal(t, jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, resp.StrategyType) require.NotNil(t, resp.RateLimitingSampling) assert.EqualValues(t, 123, resp.RateLimitingSampling.MaxTracesPerSecond) } sampling_manager.go000066400000000000000000000035001443314701600355500ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/testutils// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testutils // import "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/testutils" import ( "sync" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" ) func newSamplingManager() *samplingManager { return &samplingManager{ sampling: make(map[string]interface{}), } } type samplingManager struct { sampling map[string]interface{} mutex sync.Mutex } // GetSamplingStrategy implements handler method of sampling.SamplingManager. func (s *samplingManager) GetSamplingStrategy(serviceName string) (interface{}, error) { s.mutex.Lock() defer s.mutex.Unlock() if strategy, ok := s.sampling[serviceName]; ok { return strategy, nil } return &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{ SamplingRate: 0.01, }}, nil } // AddSamplingStrategy registers a sampling strategy for a service. func (s *samplingManager) AddSamplingStrategy(service string, strategy interface{}) { s.mutex.Lock() defer s.mutex.Unlock() s.sampling[service] = strategy } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/utils/000077500000000000000000000000001443314701600310765ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/utils/http_json.go000066400000000000000000000030551443314701600334400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils // import "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/utils" import ( "encoding/json" "fmt" "io" "net/http" ) // GetJSON makes an HTTP call to the specified URL and parses the returned JSON into `out`. func GetJSON(url string, out interface{}) error { resp, err := http.Get(url) if err != nil { return err } return ReadJSON(resp, out) } // ReadJSON reads JSON from http.Response and parses it into `out`. func ReadJSON(resp *http.Response, out interface{}) error { defer resp.Body.Close() if resp.StatusCode >= 400 { body, err := io.ReadAll(resp.Body) if err != nil { return err } return fmt.Errorf("status code: %d, body: %s", resp.StatusCode, body) } if out == nil { _, err := io.Copy(io.Discard, resp.Body) if err != nil { return err } return nil } decoder := json.NewDecoder(resp.Body) return decoder.Decode(out) } http_json_test.go000066400000000000000000000032341443314701600344170ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/utils// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type testJSONStruct struct { Name string Age int } func TestGetJSON(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") _, err := w.Write([]byte("{\"name\": \"Bender\", \"age\": 3}")) assert.NoError(t, err) })) defer server.Close() var s testJSONStruct err := GetJSON(server.URL, &s) require.NoError(t, err) assert.Equal(t, "Bender", s.Name) assert.Equal(t, 3, s.Age) } func TestGetJSONErrors(t *testing.T) { var s testJSONStruct err := GetJSON("localhost:0", &s) assert.Error(t, err) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "some error", http.StatusInternalServerError) })) defer server.Close() err = GetJSON(server.URL, &s) assert.Error(t, err) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/utils/rate_limiter.go000066400000000000000000000101211443314701600341000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils // import "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/utils" import ( "sync" "time" ) // RateLimiter is a filter used to check if a message that is worth itemCost units is within the rate limits. // // RateLimiter is a rate limiter based on leaky bucket algorithm, formulated in terms of a // credits balance that is replenished every time CheckCredit() method is called (tick) by the amount proportional // to the time elapsed since the last tick, up to max of creditsPerSecond. A call to CheckCredit() takes a cost // of an item we want to pay with the balance. If the balance exceeds the cost of the item, the item is "purchased" // and the balance reduced, indicated by returned value of true. Otherwise the balance is unchanged and return false. // // This can be used to limit a rate of messages emitted by a service by instantiating the Rate Limiter with the // max number of messages a service is allowed to emit per second, and calling CheckCredit(1.0) for each message // to determine if the message is within the rate limit. // // It can also be used to limit the rate of traffic in bytes, by setting creditsPerSecond to desired throughput // as bytes/second, and calling CheckCredit() with the actual message size. type RateLimiter struct { lock sync.Mutex creditsPerSecond float64 balance float64 maxBalance float64 lastTick time.Time timeNow func() time.Time } // NewRateLimiter creates a new RateLimiter. func NewRateLimiter(creditsPerSecond, maxBalance float64) *RateLimiter { balance := maxBalance if creditsPerSecond == 0 { balance = 0 } return &RateLimiter{ creditsPerSecond: creditsPerSecond, balance: balance, maxBalance: maxBalance, lastTick: time.Now(), timeNow: time.Now, } } // CheckCredit tries to reduce the current balance by itemCost provided that the current balance // is not lest than itemCost. func (rl *RateLimiter) CheckCredit(itemCost float64) bool { rl.lock.Lock() defer rl.lock.Unlock() // if we have enough credits to pay for current item, then reduce balance and allow if rl.balance >= itemCost { rl.balance -= itemCost return true } // otherwise check if balance can be increased due to time elapsed, and try again rl.updateBalance() if rl.balance >= itemCost { rl.balance -= itemCost return true } return false } // updateBalance recalculates current balance based on time elapsed. Must be called while holding a lock. func (rl *RateLimiter) updateBalance() { // calculate how much time passed since the last tick, and update current tick currentTime := rl.timeNow() elapsedTime := currentTime.Sub(rl.lastTick) rl.lastTick = currentTime // calculate how much credit have we accumulated since the last tick rl.balance += elapsedTime.Seconds() * rl.creditsPerSecond if rl.balance > rl.maxBalance { rl.balance = rl.maxBalance } } // Update changes the main parameters of the rate limiter in-place, while retaining // the current accumulated balance (pro-rated to the new maxBalance value). Using this method // instead of creating a new rate limiter helps to avoid thundering herd when sampling // strategies are updated. func (rl *RateLimiter) Update(creditsPerSecond, maxBalance float64) { rl.lock.Lock() defer rl.lock.Unlock() rl.updateBalance() // get up to date balance rl.balance = rl.balance * maxBalance / rl.maxBalance rl.creditsPerSecond = creditsPerSecond rl.maxBalance = maxBalance } rate_limiter_test.go000066400000000000000000000061331443314701600350700ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/internal/utils// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestRateLimiter(t *testing.T) { rl := NewRateLimiter(2.0, 2.0) // stop time ts := time.Now() rl.lastTick = ts rl.timeNow = func() time.Time { return ts } assert.True(t, rl.CheckCredit(1.0)) assert.True(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) // move time 250ms forward, not enough credits to pay for 1.0 item rl.timeNow = func() time.Time { return ts.Add(time.Second / 4) } assert.False(t, rl.CheckCredit(1.0)) // move time 500ms forward, now enough credits to pay for 1.0 item rl.timeNow = func() time.Time { return ts.Add(time.Second/4 + time.Second/2) } assert.True(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) // move time 5s forward, enough to accumulate credits for 10 messages, but it should still be capped at 2 rl.lastTick = ts rl.timeNow = func() time.Time { return ts.Add(5 * time.Second) } assert.True(t, rl.CheckCredit(1.0)) assert.True(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) } func TestRateLimiterMaxBalance(t *testing.T) { rl := NewRateLimiter(0.1, 1.0) // stop time ts := time.Now() rl.lastTick = ts rl.timeNow = func() time.Time { return ts } assert.True(t, rl.CheckCredit(1.0), "on initialization, should have enough credits for 1 message") // move time 20s forward, enough to accumulate credits for 2 messages, but it should still be capped at 1 rl.timeNow = func() time.Time { return ts.Add(time.Second * 20) } assert.True(t, rl.CheckCredit(1.0)) assert.False(t, rl.CheckCredit(1.0)) } func TestRateLimiterReconfigure(t *testing.T) { rl := NewRateLimiter(1, 1.0) assertBalance := func(expected float64) { const delta = 0.0000001 // just some precision for comparing floats assert.InDelta(t, expected, rl.balance, delta) } // stop time ts := time.Now() rl.lastTick = ts rl.timeNow = func() time.Time { return ts } assert.True(t, rl.CheckCredit(1.0), "first message must succeed") assert.False(t, rl.CheckCredit(1.0), "second message must be rejected") assertBalance(0.0) // move half-second forward rl.timeNow = func() time.Time { return ts.Add(time.Second / 2) } rl.updateBalance() assertBalance(0.5) // 50% of max rl.Update(2, 4) assertBalance(2) // 50% of max assert.EqualValues(t, 2, rl.creditsPerSecond) assert.EqualValues(t, 4, rl.maxBalance) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/jaeger-idl/000077500000000000000000000000001443314701600301255ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/jaeger-idl/proto/000077500000000000000000000000001443314701600312705ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/jaeger-idl/proto/api_v2/000077500000000000000000000000001443314701600324505ustar00rootroot00000000000000sampling.proto000066400000000000000000000046441443314701600353000ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/jaeger-idl/proto/api_v2// Copyright (c) 2019 The Jaeger Authors. // Copyright (c) 2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This package implements the Jaeger jaeger-idl specification as defined // at https://github.com/jaegertracing/jaeger-idl/blob/main/proto/api_v2/sampling.proto syntax="proto3"; package jaeger.api_v2; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; option go_package = "api_v2"; option java_package = "io.jaegertracing.api_v2"; // Enable gogoprotobuf extensions (https://github.com/gogo/protobuf/blob/master/extensions.md). // Enable custom Marshal method. option (gogoproto.marshaler_all) = true; // Enable custom Unmarshal method. option (gogoproto.unmarshaler_all) = true; // Enable custom Size method (Required by Marshal and Unmarshal). option (gogoproto.sizer_all) = true; enum SamplingStrategyType { PROBABILISTIC = 0; RATE_LIMITING = 1; }; message ProbabilisticSamplingStrategy { double samplingRate = 1; } message RateLimitingSamplingStrategy { int32 maxTracesPerSecond = 1; } message OperationSamplingStrategy { string operation = 1; ProbabilisticSamplingStrategy probabilisticSampling = 2; } message PerOperationSamplingStrategies { double defaultSamplingProbability = 1; double defaultLowerBoundTracesPerSecond = 2; repeated OperationSamplingStrategy perOperationStrategies = 3; double defaultUpperBoundTracesPerSecond = 4; } message SamplingStrategyResponse { SamplingStrategyType strategyType = 1; ProbabilisticSamplingStrategy probabilisticSampling = 2; RateLimitingSamplingStrategy rateLimitingSampling = 3; PerOperationSamplingStrategies operationSampling =4; } message SamplingStrategyParameters { string serviceName = 1; } service SamplingManager { rpc GetSamplingStrategy(SamplingStrategyParameters) returns (SamplingStrategyResponse) { option (google.api.http) = { post: "/api/v2/samplingStrategy" body: "*" }; } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/sampler.go000066400000000000000000000272331443314701600301230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" import ( "encoding/binary" "fmt" "math" "sync" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/utils" "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) const ( defaultMaxOperations = 2000 ) // ----------------------- // probabilisticSampler is a sampler that randomly samples a certain percentage // of traces. type probabilisticSampler struct { samplingRate float64 samplingBoundary uint64 } const maxRandomNumber = ^(uint64(1) << 63) // i.e. 0x7fffffffffffffff // newProbabilisticSampler creates a sampler that randomly samples a certain percentage of traces specified by the // samplingRate, in the range between 0.0 and 1.0. // // It relies on the fact that new trace IDs are 63bit random numbers themselves, thus making the sampling decision // without generating a new random number, but simply calculating if traceID < (samplingRate * 2^63). func newProbabilisticSampler(samplingRate float64) *probabilisticSampler { s := new(probabilisticSampler) return s.init(samplingRate) } func (s *probabilisticSampler) init(samplingRate float64) *probabilisticSampler { s.samplingRate = math.Max(0.0, math.Min(samplingRate, 1.0)) s.samplingBoundary = uint64(float64(maxRandomNumber) * s.samplingRate) return s } // SamplingRate returns the sampling probability this sampled was constructed with. func (s *probabilisticSampler) SamplingRate() float64 { return s.samplingRate } func (s *probabilisticSampler) ShouldSample(p trace.SamplingParameters) trace.SamplingResult { psc := oteltrace.SpanContextFromContext(p.ParentContext) traceID := binary.BigEndian.Uint64(p.TraceID[0:8]) if s.samplingBoundary >= traceID&maxRandomNumber { return trace.SamplingResult{ Decision: trace.RecordAndSample, Tracestate: psc.TraceState(), } } return trace.SamplingResult{ Decision: trace.Drop, Tracestate: psc.TraceState(), } } // Equal compares with another sampler. func (s *probabilisticSampler) Equal(other trace.Sampler) bool { if o, ok := other.(*probabilisticSampler); ok { return s.samplingBoundary == o.samplingBoundary } return false } // Update modifies in-place the sampling rate. Locking must be done externally. func (s *probabilisticSampler) Update(samplingRate float64) error { if samplingRate < 0.0 || samplingRate > 1.0 { return fmt.Errorf("sampling rate must be between 0.0 and 1.0, received %f", samplingRate) } s.init(samplingRate) return nil } func (s *probabilisticSampler) Description() string { return "probabilisticSampler{}" } // ----------------------- // rateLimitingSampler samples at most maxTracesPerSecond. The distribution of sampled traces follows // burstiness of the service, i.e. a service with uniformly distributed requests will have those // requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a // number of sequential requests can be sampled each second. type rateLimitingSampler struct { maxTracesPerSecond float64 rateLimiter *utils.RateLimiter } // newRateLimitingSampler creates new rateLimitingSampler. func newRateLimitingSampler(maxTracesPerSecond float64) *rateLimitingSampler { s := new(rateLimitingSampler) return s.init(maxTracesPerSecond) } func (s *rateLimitingSampler) init(maxTracesPerSecond float64) *rateLimitingSampler { if s.rateLimiter == nil { s.rateLimiter = utils.NewRateLimiter(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0)) } else { s.rateLimiter.Update(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0)) } s.maxTracesPerSecond = maxTracesPerSecond return s } func (s *rateLimitingSampler) ShouldSample(p trace.SamplingParameters) trace.SamplingResult { psc := oteltrace.SpanContextFromContext(p.ParentContext) if s.rateLimiter.CheckCredit(1.0) { return trace.SamplingResult{ Decision: trace.RecordAndSample, Tracestate: psc.TraceState(), } } return trace.SamplingResult{ Decision: trace.Drop, Tracestate: psc.TraceState(), } } // Update reconfigures the rate limiter, while preserving its accumulated balance. // Locking must be done externally. func (s *rateLimitingSampler) Update(maxTracesPerSecond float64) { if s.maxTracesPerSecond != maxTracesPerSecond { s.init(maxTracesPerSecond) } } // Equal compares with another sampler. func (s *rateLimitingSampler) Equal(other trace.Sampler) bool { if o, ok := other.(*rateLimitingSampler); ok { return s.maxTracesPerSecond == o.maxTracesPerSecond } return false } func (s *rateLimitingSampler) Description() string { return "rateLimitingSampler{}" } // ----------------------- // guaranteedThroughputProbabilisticSampler is a sampler that leverages both probabilisticSampler and // rateLimitingSampler. The rateLimitingSampler is used as a guaranteed lower bound sampler such that // every operation is sampled at least once in a time interval defined by the lowerBound. ie a lowerBound // of 1.0 / (60 * 10) will sample an operation at least once every 10 minutes. // // The probabilisticSampler is given higher priority when tags are emitted, ie. if IsSampled() for both // samplers return true, the tags for probabilisticSampler will be used. type guaranteedThroughputProbabilisticSampler struct { probabilisticSampler *probabilisticSampler lowerBoundSampler *rateLimitingSampler samplingRate float64 lowerBound float64 } func newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate float64) *guaranteedThroughputProbabilisticSampler { s := &guaranteedThroughputProbabilisticSampler{ lowerBoundSampler: newRateLimitingSampler(lowerBound), lowerBound: lowerBound, } s.setProbabilisticSampler(samplingRate) return s } func (s *guaranteedThroughputProbabilisticSampler) setProbabilisticSampler(samplingRate float64) { if s.probabilisticSampler == nil { s.probabilisticSampler = newProbabilisticSampler(samplingRate) } else if s.samplingRate != samplingRate { s.probabilisticSampler.init(samplingRate) } // since we don't validate samplingRate, sampler may have clamped it to [0, 1] interval s.samplingRate = s.probabilisticSampler.SamplingRate() } func (s *guaranteedThroughputProbabilisticSampler) ShouldSample(p trace.SamplingParameters) trace.SamplingResult { if result := s.probabilisticSampler.ShouldSample(p); result.Decision == trace.RecordAndSample { s.lowerBoundSampler.ShouldSample(p) return result } result := s.lowerBoundSampler.ShouldSample(p) return result } // this function should only be called while holding a Write lock. func (s *guaranteedThroughputProbabilisticSampler) update(lowerBound, samplingRate float64) { s.setProbabilisticSampler(samplingRate) if s.lowerBound != lowerBound { s.lowerBoundSampler.Update(lowerBound) s.lowerBound = lowerBound } } func (s *guaranteedThroughputProbabilisticSampler) Description() string { return "guaranteedThroughputProbabilisticSampler{}" } // ----------------------- // perOperationSampler is a delegating sampler that applies guaranteedThroughputProbabilisticSampler // on a per-operation basis. type perOperationSampler struct { sync.RWMutex samplers map[string]*guaranteedThroughputProbabilisticSampler defaultSampler *probabilisticSampler lowerBound float64 maxOperations int // see description in perOperationSamplerParams operationNameLateBinding bool } // perOperationSamplerParams defines parameters when creating perOperationSampler. type perOperationSamplerParams struct { // Max number of operations that will be tracked. Other operations will be given default strategy. MaxOperations int // Opt-in feature for applications that require late binding of span name via explicit call to SetOperationName. // When this feature is enabled, the sampler will return retryable=true from OnCreateSpan(), thus leaving // the sampling decision as non-final (and the span as writeable). This may lead to degraded performance // in applications that always provide the correct span name on oteltrace creation. // // For backwards compatibility this option is off by default. OperationNameLateBinding bool // Initial configuration of the sampling strategies (usually retrieved from the backend by Remote Sampler). Strategies *jaeger_api_v2.PerOperationSamplingStrategies } // newPerOperationSampler returns a new perOperationSampler. func newPerOperationSampler(params perOperationSamplerParams) *perOperationSampler { if params.MaxOperations <= 0 { params.MaxOperations = defaultMaxOperations } samplers := make(map[string]*guaranteedThroughputProbabilisticSampler) for _, strategy := range params.Strategies.PerOperationStrategies { sampler := newGuaranteedThroughputProbabilisticSampler( params.Strategies.DefaultLowerBoundTracesPerSecond, strategy.ProbabilisticSampling.SamplingRate, ) samplers[strategy.Operation] = sampler } return &perOperationSampler{ samplers: samplers, defaultSampler: newProbabilisticSampler(params.Strategies.DefaultSamplingProbability), lowerBound: params.Strategies.DefaultLowerBoundTracesPerSecond, maxOperations: params.MaxOperations, operationNameLateBinding: params.OperationNameLateBinding, } } func (s *perOperationSampler) ShouldSample(p trace.SamplingParameters) trace.SamplingResult { sampler := s.getSamplerForOperation(p.Name) return sampler.ShouldSample(p) } func (s *perOperationSampler) getSamplerForOperation(operation string) trace.Sampler { s.RLock() sampler, ok := s.samplers[operation] if ok { defer s.RUnlock() return sampler } s.RUnlock() s.Lock() defer s.Unlock() // Check if sampler has already been created sampler, ok = s.samplers[operation] if ok { return sampler } // Store only up to maxOperations of unique ops. if len(s.samplers) >= s.maxOperations { return s.defaultSampler } newSampler := newGuaranteedThroughputProbabilisticSampler(s.lowerBound, s.defaultSampler.SamplingRate()) s.samplers[operation] = newSampler return newSampler } func (s *perOperationSampler) Description() string { return "perOperationSampler{}" } func (s *perOperationSampler) update(strategies *jaeger_api_v2.PerOperationSamplingStrategies) { s.Lock() defer s.Unlock() newSamplers := map[string]*guaranteedThroughputProbabilisticSampler{} for _, strategy := range strategies.PerOperationStrategies { operation := strategy.Operation samplingRate := strategy.ProbabilisticSampling.SamplingRate lowerBound := strategies.DefaultLowerBoundTracesPerSecond if sampler, ok := s.samplers[operation]; ok { sampler.update(lowerBound, samplingRate) newSamplers[operation] = sampler } else { sampler := newGuaranteedThroughputProbabilisticSampler( lowerBound, samplingRate, ) newSamplers[operation] = sampler } } s.lowerBound = strategies.DefaultLowerBoundTracesPerSecond if s.defaultSampler.SamplingRate() != strategies.DefaultSamplingProbability { s.defaultSampler = newProbabilisticSampler(strategies.DefaultSamplingProbability) } s.samplers = newSamplers } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/sampler_remote.go000066400000000000000000000233101443314701600314660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" import ( "bytes" "fmt" "io" "net/http" "net/url" "sync" "sync/atomic" "time" "github.com/gogo/protobuf/jsonpb" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" "go.opentelemetry.io/otel/sdk/trace" ) const ( defaultRemoteSamplingTimeout = 10 * time.Second defaultSamplingRefreshInterval = time.Minute defaultSamplingMaxOperations = 256 defaultSamplingOperationNameLateBinding = true ) // samplingStrategyFetcher is used to fetch sampling strategy updates from remote server. type samplingStrategyFetcher interface { Fetch(service string) ([]byte, error) } // samplingStrategyParser is used to parse sampling strategy updates. The output object // should be of the type that is recognized by the SamplerUpdaters. type samplingStrategyParser interface { Parse(response []byte) (interface{}, error) } // samplerUpdater is used by Sampler to apply sampling strategies, // retrieved from remote config server, to the current sampler. The updater can modify // the sampler in-place if sampler supports it, or create a new one. // // If the strategy does not contain configuration for the sampler in question, // updater must return modifiedSampler=nil to give other updaters a chance to inspect // the sampling strategy response. // // Sampler invokes the updaters while holding a lock on the main sampler. type samplerUpdater interface { Update(sampler trace.Sampler, strategy interface{}) (modified trace.Sampler, err error) } // Sampler is a delegating sampler that polls a remote server // for the appropriate sampling strategy, constructs a corresponding sampler and // delegates to it for sampling decisions. type Sampler struct { // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq closed int64 // 0 - not closed, 1 - closed sync.RWMutex // used to serialize access to samplerConfig.sampler config serviceName string doneChan chan *sync.WaitGroup } // New creates a sampler that periodically pulls // the sampling strategy from an HTTP sampling server (e.g. jaeger-agent). func New( serviceName string, opts ...Option, ) *Sampler { options := newConfig(opts...) sampler := &Sampler{ config: options, serviceName: serviceName, doneChan: make(chan *sync.WaitGroup), } go sampler.pollController() return sampler } // ShouldSample returns a sampling choice based on the passed sampling // parameters. func (s *Sampler) ShouldSample(p trace.SamplingParameters) trace.SamplingResult { s.RLock() defer s.RUnlock() return s.sampler.ShouldSample(p) } // Close does a clean shutdown of the sampler, stopping any background // go-routines it may have started. func (s *Sampler) Close() { if swapped := atomic.CompareAndSwapInt64(&s.closed, 0, 1); !swapped { s.logger.Info("repeated attempt to close the sampler is ignored") return } var wg sync.WaitGroup wg.Add(1) s.doneChan <- &wg wg.Wait() } // Description returns a human-readable name for the Sampler. func (s *Sampler) Description() string { return "JaegerRemoteSampler{}" } func (s *Sampler) pollController() { ticker := time.NewTicker(s.samplingRefreshInterval) defer ticker.Stop() s.pollControllerWithTicker(ticker) } func (s *Sampler) pollControllerWithTicker(ticker *time.Ticker) { s.UpdateSampler() for { select { case <-ticker.C: s.UpdateSampler() case wg := <-s.doneChan: wg.Done() return } } } func (s *Sampler) setSampler(sampler trace.Sampler) { s.Lock() defer s.Unlock() s.sampler = sampler } // UpdateSampler forces the sampler to fetch sampling strategy from backend server. // This function is called automatically on a timer, but can also be safely called manually, e.g. from tests. func (s *Sampler) UpdateSampler() { res, err := s.samplingFetcher.Fetch(s.serviceName) if err != nil { s.logger.Error(err, "failed to fetch sampling strategy") return } strategy, err := s.samplingParser.Parse(res) if err != nil { s.logger.Error(err, "failed to parse sampling strategy response") return } s.Lock() defer s.Unlock() if err := s.updateSamplerViaUpdaters(strategy); err != nil { s.logger.Error(err, "failed to handle sampling strategy response", "response", res) return } } // NB: this function should only be called while holding a Write lock. func (s *Sampler) updateSamplerViaUpdaters(strategy interface{}) error { for _, updater := range s.updaters { sampler, err := updater.Update(s.sampler, strategy) if err != nil { return err } if sampler != nil { s.sampler = sampler return nil } } return fmt.Errorf("unsupported sampling strategy %+v", strategy) } // ----------------------- // probabilisticSamplerUpdater is used by Sampler to parse sampling configuration. type probabilisticSamplerUpdater struct{} // Update implements Update of samplerUpdater. func (u *probabilisticSamplerUpdater) Update(sampler trace.Sampler, strategy interface{}) (trace.Sampler, error) { type response interface { GetProbabilisticSampling() *jaeger_api_v2.ProbabilisticSamplingStrategy } var _ response = new(jaeger_api_v2.SamplingStrategyResponse) // sanity signature check if resp, ok := strategy.(response); ok { if probabilistic := resp.GetProbabilisticSampling(); probabilistic != nil { if ps, ok := sampler.(*probabilisticSampler); ok { if err := ps.Update(probabilistic.SamplingRate); err != nil { return nil, err } return sampler, nil } return newProbabilisticSampler(probabilistic.SamplingRate), nil } } return nil, nil } // ----------------------- // rateLimitingSamplerUpdater is used by Sampler to parse sampling configuration. type rateLimitingSamplerUpdater struct{} // Update implements Update of samplerUpdater. func (u *rateLimitingSamplerUpdater) Update(sampler trace.Sampler, strategy interface{}) (trace.Sampler, error) { type response interface { GetRateLimitingSampling() *jaeger_api_v2.RateLimitingSamplingStrategy } var _ response = new(jaeger_api_v2.SamplingStrategyResponse) // sanity signature check if resp, ok := strategy.(response); ok { if rateLimiting := resp.GetRateLimitingSampling(); rateLimiting != nil { rateLimit := float64(rateLimiting.MaxTracesPerSecond) if rl, ok := sampler.(*rateLimitingSampler); ok { rl.Update(rateLimit) return rl, nil } return newRateLimitingSampler(rateLimit), nil } } return nil, nil } // ----------------------- // perOperationSamplerUpdater is used by Sampler to parse sampling configuration. // Fields have the same meaning as in perOperationSamplerParams. type perOperationSamplerUpdater struct { MaxOperations int OperationNameLateBinding bool } // Update implements Update of samplerUpdater. func (u *perOperationSamplerUpdater) Update(sampler trace.Sampler, strategy interface{}) (trace.Sampler, error) { type response interface { GetOperationSampling() *jaeger_api_v2.PerOperationSamplingStrategies } var _ response = new(jaeger_api_v2.SamplingStrategyResponse) // sanity signature check if p, ok := strategy.(response); ok { if operations := p.GetOperationSampling(); operations != nil { if as, ok := sampler.(*perOperationSampler); ok { as.update(operations) return as, nil } return newPerOperationSampler(perOperationSamplerParams{ MaxOperations: u.MaxOperations, OperationNameLateBinding: u.OperationNameLateBinding, Strategies: operations, }), nil } } return nil, nil } // ----------------------- type httpSamplingStrategyFetcher struct { serverURL string httpClient http.Client } func newHTTPSamplingStrategyFetcher(serverURL string) *httpSamplingStrategyFetcher { customTransport := http.DefaultTransport.(*http.Transport).Clone() customTransport.ResponseHeaderTimeout = defaultRemoteSamplingTimeout return &httpSamplingStrategyFetcher{ serverURL: serverURL, httpClient: http.Client{ Transport: customTransport, }, } } func (f *httpSamplingStrategyFetcher) Fetch(serviceName string) ([]byte, error) { v := url.Values{} v.Set("service", serviceName) uri := f.serverURL + "?" + v.Encode() resp, err := f.httpClient.Get(uri) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } if resp.StatusCode >= 400 { return nil, fmt.Errorf("status code: %d, body: %c", resp.StatusCode, body) } return body, nil } // ----------------------- type samplingStrategyParserImpl struct{} func (p *samplingStrategyParserImpl) Parse(response []byte) (interface{}, error) { strategy := new(jaeger_api_v2.SamplingStrategyResponse) // Official Jaeger Remote Sampling protocol contains enums encoded as strings. // Legacy protocol contains enums as numbers. // Gogo's jsonpb module can parse either format. // Cf. https://github.com/open-telemetry/opentelemetry-go-contrib/issues/3184 if err := jsonpb.Unmarshal(bytes.NewReader(response), strategy); err != nil { return nil, err } return strategy, nil } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/sampler_remote_options.go000066400000000000000000000114111443314701600332400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" import ( "time" "github.com/go-logr/logr" "go.opentelemetry.io/otel/sdk/trace" ) type config struct { sampler trace.Sampler samplingServerURL string samplingRefreshInterval time.Duration samplingFetcher samplingStrategyFetcher samplingParser samplingStrategyParser updaters []samplerUpdater posParams perOperationSamplerParams logger logr.Logger } // newConfig returns an appropriately configured config. func newConfig(options ...Option) config { c := config{ sampler: newProbabilisticSampler(0.001), samplingServerURL: defaultSamplingServerURL, samplingRefreshInterval: defaultSamplingRefreshInterval, samplingFetcher: newHTTPSamplingStrategyFetcher(defaultSamplingServerURL), samplingParser: new(samplingStrategyParserImpl), updaters: []samplerUpdater{ new(probabilisticSamplerUpdater), new(rateLimitingSamplerUpdater), }, posParams: perOperationSamplerParams{ MaxOperations: defaultSamplingMaxOperations, OperationNameLateBinding: defaultSamplingOperationNameLateBinding, }, logger: logr.Discard(), } for _, option := range options { option.apply(&c) } c.updaters = append([]samplerUpdater{&perOperationSamplerUpdater{ MaxOperations: c.posParams.MaxOperations, OperationNameLateBinding: c.posParams.OperationNameLateBinding, }}, c.updaters...) return c } // Option applies configuration settings to a Sampler. type Option interface { apply(*config) } type optionFunc func(*config) func (fn optionFunc) apply(c *config) { fn(c) } // WithInitialSampler creates a Option that sets the initial sampler // to use before a remote sampler is created and used. func WithInitialSampler(sampler trace.Sampler) Option { return optionFunc(func(c *config) { c.sampler = sampler }) } // WithSamplingServerURL creates a Option that sets the sampling server url // of the local agent that contains the sampling strategies. func WithSamplingServerURL(samplingServerURL string) Option { return optionFunc(func(c *config) { c.samplingServerURL = samplingServerURL // The default port of jaeger agent is 5778, but there are other ports specified by the user, so the sampling address and fetch address are strongly bound c.samplingFetcher = newHTTPSamplingStrategyFetcher(samplingServerURL) }) } // WithMaxOperations creates a Option that sets the maximum number of // operations the sampler will keep track of. func WithMaxOperations(maxOperations int) Option { return optionFunc(func(c *config) { c.posParams.MaxOperations = maxOperations }) } // WithOperationNameLateBinding creates a Option that sets the respective // field in the perOperationSamplerParams. func WithOperationNameLateBinding(enable bool) Option { return optionFunc(func(c *config) { c.posParams.OperationNameLateBinding = enable }) } // WithSamplingRefreshInterval creates a Option that sets how often the // sampler will poll local agent for the appropriate sampling strategy. func WithSamplingRefreshInterval(samplingRefreshInterval time.Duration) Option { return optionFunc(func(c *config) { c.samplingRefreshInterval = samplingRefreshInterval }) } // WithLogger configures the sampler to log operation and debug information with logger. func WithLogger(logger logr.Logger) Option { return optionFunc(func(c *config) { c.logger = logger }) } // samplingStrategyFetcher creates a Option that initializes sampling strategy fetcher. func withSamplingStrategyFetcher(fetcher samplingStrategyFetcher) Option { return optionFunc(func(c *config) { c.samplingFetcher = fetcher }) } // samplingStrategyParser creates a Option that initializes sampling strategy parser. func withSamplingStrategyParser(parser samplingStrategyParser) Option { return optionFunc(func(c *config) { c.samplingParser = parser }) } // withUpdaters creates a Option that initializes sampler updaters. func withUpdaters(updaters ...samplerUpdater) Option { return optionFunc(func(c *config) { c.updaters = updaters }) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/sampler_remote_test.go000066400000000000000000000500001443314701600325210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote import ( "encoding/binary" "errors" "fmt" "testing" "time" "github.com/go-logr/logr/testr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/testutils" "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) func TestRemotelyControlledSampler_updateRace(t *testing.T) { initSampler := newProbabilisticSampler(0.123) fetcher := &testSamplingStrategyFetcher{response: []byte("probabilistic")} parser := new(testSamplingStrategyParser) updaters := []samplerUpdater{new(probabilisticSamplerUpdater)} sampler := New( "test", WithMaxOperations(42), WithOperationNameLateBinding(true), WithInitialSampler(initSampler), WithSamplingServerURL("my url"), WithSamplingRefreshInterval(time.Millisecond), withSamplingStrategyFetcher(fetcher), withSamplingStrategyParser(parser), withUpdaters(updaters...), ) s := makeSamplingParameters(1, "test") end := make(chan struct{}) accessor := func(f func()) { for { select { case <-end: return default: f() } } } go accessor(func() { sampler.UpdateSampler() }) go accessor(func() { sampler.ShouldSample(s) }) time.Sleep(100 * time.Millisecond) close(end) sampler.Close() } type testSamplingStrategyFetcher struct { response []byte } func (c *testSamplingStrategyFetcher) Fetch(serviceName string) ([]byte, error) { return c.response, nil } type testSamplingStrategyParser struct { } func (p *testSamplingStrategyParser) Parse(response []byte) (interface{}, error) { strategy := new(jaeger_api_v2.SamplingStrategyResponse) switch string(response) { case "probabilistic": strategy.StrategyType = jaeger_api_v2.SamplingStrategyType_PROBABILISTIC strategy.ProbabilisticSampling = &jaeger_api_v2.ProbabilisticSamplingStrategy{ SamplingRate: 0.85, } return strategy, nil case "rateLimiting": strategy.StrategyType = jaeger_api_v2.SamplingStrategyType_RATE_LIMITING strategy.RateLimitingSampling = &jaeger_api_v2.RateLimitingSamplingStrategy{ MaxTracesPerSecond: 100, } return strategy, nil } return nil, errors.New("unknown strategy test request") } func TestRemoteSamplerOptions(t *testing.T) { initSampler := newProbabilisticSampler(0.123) fetcher := new(fakeSamplingFetcher) parser := new(samplingStrategyParserImpl) logger := testr.New(t) updaters := []samplerUpdater{new(probabilisticSamplerUpdater)} sampler := New( "test", WithMaxOperations(42), WithOperationNameLateBinding(true), WithInitialSampler(initSampler), WithSamplingServerURL("my url"), WithSamplingRefreshInterval(42*time.Second), withSamplingStrategyFetcher(fetcher), withSamplingStrategyParser(parser), withUpdaters(updaters...), WithLogger(logger), ) assert.Equal(t, 42, sampler.posParams.MaxOperations) assert.True(t, sampler.posParams.OperationNameLateBinding) assert.Same(t, initSampler, sampler.sampler) assert.Equal(t, "my url", sampler.samplingServerURL) assert.Equal(t, 42*time.Second, sampler.samplingRefreshInterval) assert.Same(t, fetcher, sampler.samplingFetcher) assert.Same(t, parser, sampler.samplingParser) assert.EqualValues(t, sampler.updaters[0], &perOperationSamplerUpdater{MaxOperations: 42, OperationNameLateBinding: true}) assert.Equal(t, logger, sampler.logger) } func TestRemoteSamplerOptionsDefaults(t *testing.T) { options := newConfig() sampler, ok := options.sampler.(*probabilisticSampler) assert.True(t, ok) assert.Equal(t, 0.001, sampler.samplingRate) assert.NotEmpty(t, options.samplingServerURL) assert.NotZero(t, options.samplingRefreshInterval) } func initAgent(t *testing.T) (*testutils.MockAgent, *Sampler) { agent, err := testutils.StartMockAgent() require.NoError(t, err) initialSampler := newProbabilisticSampler(0.001) sampler := New( "client app", WithSamplingServerURL("http://"+agent.SamplingServerAddr()), WithMaxOperations(testDefaultMaxOperations), WithInitialSampler(initialSampler), WithSamplingRefreshInterval(time.Minute), ) sampler.Close() // stop timer-based updates, we want to call them manually return agent, sampler } func makeSamplingParameters(id uint64, operationName string) trace.SamplingParameters { var traceID oteltrace.TraceID binary.BigEndian.PutUint64(traceID[:], id) return trace.SamplingParameters{ TraceID: traceID, Name: operationName, } } func TestRemotelyControlledSampler(t *testing.T) { agent, remoteSampler := initAgent(t) defer agent.Close() defaultSampler := newProbabilisticSampler(0.001) remoteSampler.setSampler(defaultSampler) agent.AddSamplingStrategy("client app", getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, testDefaultSamplingProbability)) remoteSampler.UpdateSampler() s1, ok := remoteSampler.sampler.(*probabilisticSampler) assert.True(t, ok) assert.EqualValues(t, testDefaultSamplingProbability, s1.samplingRate, "Sampler should have been updated") result := remoteSampler.ShouldSample(makeSamplingParameters(testMaxID+10, testOperationName)) assert.Equal(t, trace.Drop, result.Decision) result = remoteSampler.ShouldSample(makeSamplingParameters(testMaxID-10, testOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) remoteSampler.setSampler(defaultSampler) c := make(chan time.Time) ticker := &time.Ticker{C: c} // reset closed so the next call to Close() correctly stops the polling goroutine remoteSampler.closed = 0 go remoteSampler.pollControllerWithTicker(ticker) c <- time.Now() // force update based on timer time.Sleep(10 * time.Millisecond) remoteSampler.Close() s2, ok := remoteSampler.sampler.(*probabilisticSampler) assert.True(t, ok) assert.EqualValues(t, testDefaultSamplingProbability, s2.samplingRate, "Sampler should have been updated from timer") } func TestRemotelyControlledSampler_updateSampler(t *testing.T) { tests := []struct { probabilities map[string]float64 defaultProbability float64 expectedDefaultProbability float64 }{ { probabilities: map[string]float64{testOperationName: 1.1}, defaultProbability: testDefaultSamplingProbability, expectedDefaultProbability: testDefaultSamplingProbability, }, { probabilities: map[string]float64{testOperationName: testDefaultSamplingProbability}, defaultProbability: testDefaultSamplingProbability, expectedDefaultProbability: testDefaultSamplingProbability, }, { probabilities: map[string]float64{ testOperationName: testDefaultSamplingProbability, testFirstTimeOperationName: testDefaultSamplingProbability, }, defaultProbability: testDefaultSamplingProbability, expectedDefaultProbability: testDefaultSamplingProbability, }, { probabilities: map[string]float64{"new op": 1.1}, defaultProbability: testDefaultSamplingProbability, expectedDefaultProbability: testDefaultSamplingProbability, }, { probabilities: map[string]float64{"new op": 1.1}, defaultProbability: 1.1, expectedDefaultProbability: 1.0, }, } for i, test := range tests { t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { agent, sampler := initAgent(t) defer agent.Close() initSampler, ok := sampler.sampler.(*probabilisticSampler) assert.True(t, ok) res := &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, OperationSampling: &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: test.defaultProbability, DefaultLowerBoundTracesPerSecond: 0.001, }, } for opName, prob := range test.probabilities { res.OperationSampling.PerOperationStrategies = append(res.OperationSampling.PerOperationStrategies, &jaeger_api_v2.OperationSamplingStrategy{ Operation: opName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{ SamplingRate: prob, }, }, ) } agent.AddSamplingStrategy("client app", res) sampler.UpdateSampler() s, ok := sampler.sampler.(*perOperationSampler) assert.True(t, ok) assert.NotEqual(t, initSampler, sampler.sampler, "Sampler should have been updated") assert.Equal(t, test.expectedDefaultProbability, s.defaultSampler.SamplingRate()) // First call is always sampled result := sampler.ShouldSample(makeSamplingParameters(testMaxID+10, testOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(makeSamplingParameters(testMaxID-10, testOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) }) } } func TestRemotelyControlledSampler_ImmediatelyUpdateOnStartup(t *testing.T) { initSampler := newProbabilisticSampler(0.123) fetcher := &testSamplingStrategyFetcher{response: []byte("rateLimiting")} parser := new(testSamplingStrategyParser) updaters := []samplerUpdater{new(probabilisticSamplerUpdater), new(rateLimitingSamplerUpdater)} sampler := New( "test", WithMaxOperations(42), WithOperationNameLateBinding(true), WithInitialSampler(initSampler), WithSamplingServerURL("my url"), WithSamplingRefreshInterval(10*time.Minute), withSamplingStrategyFetcher(fetcher), withSamplingStrategyParser(parser), withUpdaters(updaters...), ) time.Sleep(100 * time.Millisecond) // waiting for s.pollController sampler.Close() // stop pollController, avoid date race s, ok := sampler.sampler.(*rateLimitingSampler) assert.True(t, ok) assert.Equal(t, float64(100), s.maxTracesPerSecond) } func TestRemotelyControlledSampler_multiStrategyResponse(t *testing.T) { agent, sampler := initAgent(t) defer agent.Close() initSampler, ok := sampler.sampler.(*probabilisticSampler) assert.True(t, ok) defaultSampingRate := 1.0 testUnusedOpName := "unused_op" testUnusedOpSamplingRate := 0.0 res := &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: defaultSampingRate}, OperationSampling: &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: defaultSampingRate, DefaultLowerBoundTracesPerSecond: 0.001, PerOperationStrategies: []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testUnusedOpName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{ SamplingRate: testUnusedOpSamplingRate, }}, }, }, } agent.AddSamplingStrategy("client app", res) sampler.UpdateSampler() s, ok := sampler.sampler.(*perOperationSampler) assert.True(t, ok) assert.NotEqual(t, initSampler, sampler.sampler, "Sampler should have been updated") assert.Equal(t, defaultSampingRate, s.defaultSampler.SamplingRate()) result := sampler.ShouldSample(makeSamplingParameters(testMaxID-10, testUnusedOpName)) assert.Equal(t, trace.RecordAndSample, result.Decision) // first call always pass result = sampler.ShouldSample(makeSamplingParameters(testMaxID, testUnusedOpName)) assert.Equal(t, trace.Drop, result.Decision) } func TestSamplerQueryError(t *testing.T) { agent, sampler := initAgent(t) defer agent.Close() // override the actual handler sampler.samplingFetcher = &fakeSamplingFetcher{} initSampler, ok := sampler.sampler.(*probabilisticSampler) assert.True(t, ok) sampler.Close() // stop timer-based updates, we want to call them manually sampler.UpdateSampler() assert.Equal(t, initSampler, sampler.sampler, "Sampler should not have been updated due to query error") } type fakeSamplingFetcher struct{} func (c *fakeSamplingFetcher) Fetch(serviceName string) ([]byte, error) { return nil, errors.New("query error") } func TestRemotelyControlledSampler_updateSamplerFromAdaptiveSampler(t *testing.T) { agent, remoteSampler := initAgent(t) defer agent.Close() remoteSampler.Close() // close the second time (initAgent already called Close) strategies := &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: testDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: 1.0, } adaptiveSampler := newPerOperationSampler(perOperationSamplerParams{ MaxOperations: testDefaultMaxOperations, Strategies: strategies, }) // Overwrite the sampler with an adaptive sampler remoteSampler.setSampler(adaptiveSampler) agent.AddSamplingStrategy("client app", getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, 0.5)) remoteSampler.UpdateSampler() // Sampler should have been updated to probabilistic _, ok := remoteSampler.sampler.(*probabilisticSampler) require.True(t, ok) // Overwrite the sampler with an adaptive sampler remoteSampler.setSampler(adaptiveSampler) agent.AddSamplingStrategy("client app", getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, 1)) remoteSampler.UpdateSampler() // Sampler should have been updated to ratelimiting _, ok = remoteSampler.sampler.(*rateLimitingSampler) require.True(t, ok) // Overwrite the sampler with an adaptive sampler remoteSampler.setSampler(adaptiveSampler) // Update existing adaptive sampler agent.AddSamplingStrategy("client app", &jaeger_api_v2.SamplingStrategyResponse{OperationSampling: strategies}) remoteSampler.UpdateSampler() } func TestRemotelyControlledSampler_updateRateLimitingOrProbabilisticSampler(t *testing.T) { probabilisticSampler := newProbabilisticSampler(0.002) otherProbabilisticSampler := newProbabilisticSampler(0.003) maxProbabilisticSampler := newProbabilisticSampler(1.0) rateLimitingSampler := newRateLimitingSampler(2) otherRateLimitingSampler := newRateLimitingSampler(3) testCases := []struct { res *jaeger_api_v2.SamplingStrategyResponse initSampler trace.Sampler expectedSampler trace.Sampler shouldErr bool referenceEquivalence bool caption string }{ { res: getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, 1.5), initSampler: probabilisticSampler, expectedSampler: maxProbabilisticSampler, shouldErr: true, referenceEquivalence: false, caption: "invalid probabilistic strategy", }, { res: getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, 0.002), initSampler: probabilisticSampler, expectedSampler: probabilisticSampler, shouldErr: false, referenceEquivalence: true, caption: "unchanged probabilistic strategy", }, { res: getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, 0.003), initSampler: probabilisticSampler, expectedSampler: otherProbabilisticSampler, shouldErr: false, referenceEquivalence: false, caption: "valid probabilistic strategy", }, { res: getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, 2), initSampler: rateLimitingSampler, expectedSampler: rateLimitingSampler, shouldErr: false, referenceEquivalence: true, caption: "unchanged rate limiting strategy", }, { res: getSamplingStrategyResponse(jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, 3), initSampler: rateLimitingSampler, expectedSampler: otherRateLimitingSampler, shouldErr: false, referenceEquivalence: false, caption: "valid rate limiting strategy", }, { res: &jaeger_api_v2.SamplingStrategyResponse{}, initSampler: rateLimitingSampler, expectedSampler: rateLimitingSampler, shouldErr: true, referenceEquivalence: true, caption: "invalid strategy", }, } for _, tc := range testCases { testCase := tc // capture loop var t.Run(testCase.caption, func(t *testing.T) { remoteSampler := New( "test", WithInitialSampler(testCase.initSampler), withUpdaters( new(probabilisticSamplerUpdater), new(rateLimitingSamplerUpdater), ), ) err := remoteSampler.updateSamplerViaUpdaters(testCase.res) if testCase.shouldErr { require.Error(t, err) return } if testCase.referenceEquivalence { assert.Equal(t, testCase.expectedSampler, remoteSampler.sampler) } else { type comparable interface { Equal(other trace.Sampler) bool } es, esOk := testCase.expectedSampler.(comparable) require.True(t, esOk, "expected sampler %+v must implement Equal()", testCase.expectedSampler) assert.True(t, es.Equal(remoteSampler.sampler), "sampler.Equal: want=%+v, have=%+v", testCase.expectedSampler, remoteSampler.sampler) } }) } } func getSamplingStrategyResponse(strategyType jaeger_api_v2.SamplingStrategyType, value float64) *jaeger_api_v2.SamplingStrategyResponse { if strategyType == jaeger_api_v2.SamplingStrategyType_PROBABILISTIC { return &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_PROBABILISTIC, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{ SamplingRate: value, }, } } if strategyType == jaeger_api_v2.SamplingStrategyType_RATE_LIMITING { return &jaeger_api_v2.SamplingStrategyResponse{ StrategyType: jaeger_api_v2.SamplingStrategyType_RATE_LIMITING, RateLimitingSampling: &jaeger_api_v2.RateLimitingSamplingStrategy{ MaxTracesPerSecond: int32(value), }, } } return nil } func TestSamplingStrategyParserImpl(t *testing.T) { assertProbabilistic := func(t *testing.T, s *jaeger_api_v2.SamplingStrategyResponse) { require.NotNil(t, s.GetProbabilisticSampling(), "output: %+v", s) require.EqualValues(t, 0.42, s.GetProbabilisticSampling().GetSamplingRate(), "output: %+v", s) } assertRateLimiting := func(t *testing.T, s *jaeger_api_v2.SamplingStrategyResponse) { require.NotNil(t, s.GetRateLimitingSampling(), "output: %+v", s) require.EqualValues(t, 42, s.GetRateLimitingSampling().GetMaxTracesPerSecond(), "output: %+v", s) } tests := []struct { name string json string assert func(t *testing.T, s *jaeger_api_v2.SamplingStrategyResponse) }{ { name: "official JSON probabilistic", json: `{"strategyType":"PROBABILISTIC","probabilisticSampling":{"samplingRate":0.42}}`, assert: assertProbabilistic, }, { name: "official JSON rate limiting", json: `{"strategyType":"RATE_LIMITING","rateLimitingSampling":{"maxTracesPerSecond":42}}`, assert: assertRateLimiting, }, { name: "legacy JSON probabilistic", json: `{"strategyType":0,"probabilisticSampling":{"samplingRate":0.42}}`, assert: assertProbabilistic, }, { name: "legacy JSON rate limiting", json: `{"strategyType":1,"rateLimitingSampling":{"maxTracesPerSecond":42}}`, assert: assertRateLimiting, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { val, err := new(samplingStrategyParserImpl).Parse([]byte(test.json)) require.NoError(t, err) s := val.(*jaeger_api_v2.SamplingStrategyResponse) test.assert(t, s) }) } } func TestSamplingStrategyParserImpl_Error(t *testing.T) { json := `{"strategyType":"foo_bar","probabilisticSampling":{"samplingRate":0.42}}` val, err := new(samplingStrategyParserImpl).Parse([]byte(json)) require.Error(t, err, "output: %+v", val) require.Contains(t, err.Error(), `unknown value "foo_bar"`) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/sampler_test.go000066400000000000000000000211701443314701600311540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright (c) 2021 The Jaeger Authors. // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote import ( "encoding/binary" "testing" "github.com/stretchr/testify/assert" jaeger_api_v2 "go.opentelemetry.io/contrib/samplers/jaegerremote/internal/proto-gen/jaeger-idl/proto/api_v2" "go.opentelemetry.io/otel/sdk/trace" oteltrace "go.opentelemetry.io/otel/trace" ) const ( testOperationName = "op" testFirstTimeOperationName = "firstTimeOp" testDefaultSamplingProbability = 0.5 testMaxID = uint64(1) << 62 testDefaultMaxOperations = 10 ) func TestProbabilisticSampler(t *testing.T) { var traceID oteltrace.TraceID sampler := newProbabilisticSampler(0.5) binary.BigEndian.PutUint64(traceID[:], testMaxID+10) result := sampler.ShouldSample(trace.SamplingParameters{TraceID: traceID}) assert.Equal(t, trace.Drop, result.Decision) binary.BigEndian.PutUint64(traceID[:], testMaxID-20) result = sampler.ShouldSample(trace.SamplingParameters{TraceID: traceID}) assert.Equal(t, trace.RecordAndSample, result.Decision) t.Run("test_64bit_id", func(t *testing.T) { binary.BigEndian.PutUint64(traceID[:], (testMaxID+10)|1<<63) result = sampler.ShouldSample(trace.SamplingParameters{TraceID: traceID}) assert.Equal(t, trace.Drop, result.Decision) binary.BigEndian.PutUint64(traceID[:], (testMaxID-20)|1<<63) result = sampler.ShouldSample(trace.SamplingParameters{TraceID: traceID}) assert.Equal(t, trace.RecordAndSample, result.Decision) }) } func TestRateLimitingSampler(t *testing.T) { sampler := newRateLimitingSampler(2) result := sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.Drop, result.Decision) sampler = newRateLimitingSampler(0.1) result = sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.Drop, result.Decision) sampler = newRateLimitingSampler(0) result = sampler.ShouldSample(trace.SamplingParameters{Name: testOperationName}) assert.Equal(t, trace.Drop, result.Decision) } func TestGuaranteedThroughputProbabilisticSamplerUpdate(t *testing.T) { samplingRate := 0.5 lowerBound := 2.0 sampler := newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate) assert.Equal(t, lowerBound, sampler.lowerBound) assert.Equal(t, samplingRate, sampler.samplingRate) newSamplingRate := 0.6 newLowerBound := 1.0 sampler.update(newLowerBound, newSamplingRate) assert.Equal(t, newLowerBound, sampler.lowerBound) assert.Equal(t, newSamplingRate, sampler.samplingRate) newSamplingRate = 1.1 sampler.update(newLowerBound, newSamplingRate) assert.Equal(t, 1.0, sampler.samplingRate) } func TestAdaptiveSampler(t *testing.T) { samplingRates := []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: testDefaultSamplingProbability}, }, } strategies := &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: testDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: 1.0, PerOperationStrategies: samplingRates, } sampler := newPerOperationSampler(perOperationSamplerParams{ Strategies: strategies, MaxOperations: 42, }) assert.Equal(t, 42, sampler.maxOperations) sampler = newPerOperationSampler(perOperationSamplerParams{Strategies: strategies}) assert.Equal(t, sampler.maxOperations, 2000, "default MaxOperations applied") sampler = newPerOperationSampler(perOperationSamplerParams{ MaxOperations: testDefaultMaxOperations, Strategies: strategies, }) result := sampler.ShouldSample(makeSamplingParameters(testMaxID+10, testOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(makeSamplingParameters(testMaxID-20, testOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) result = sampler.ShouldSample(makeSamplingParameters(testMaxID+10, testOperationName)) assert.Equal(t, trace.Drop, result.Decision) // This operation is seen for the first time by the sampler result = sampler.ShouldSample(makeSamplingParameters(testMaxID, testFirstTimeOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) } func TestAdaptiveSamplerErrors(t *testing.T) { strategies := &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: testDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: 2.0, PerOperationStrategies: []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: -0.1}, }, }, } sampler := newPerOperationSampler(perOperationSamplerParams{ MaxOperations: testDefaultMaxOperations, Strategies: strategies, }) assert.Equal(t, 0.0, sampler.samplers[testOperationName].samplingRate) strategies.PerOperationStrategies[0].ProbabilisticSampling.SamplingRate = 1.1 sampler = newPerOperationSampler(perOperationSamplerParams{ MaxOperations: testDefaultMaxOperations, Strategies: strategies, }) assert.Equal(t, 1.0, sampler.samplers[testOperationName].samplingRate) } func TestAdaptiveSamplerUpdate(t *testing.T) { samplingRate := 0.1 lowerBound := 2.0 samplingRates := []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: samplingRate}, }, } strategies := &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: testDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: lowerBound, PerOperationStrategies: samplingRates, } sampler := newPerOperationSampler(perOperationSamplerParams{ MaxOperations: testDefaultMaxOperations, Strategies: strategies, }) assert.Equal(t, lowerBound, sampler.lowerBound) assert.Equal(t, testDefaultSamplingProbability, sampler.defaultSampler.SamplingRate()) assert.Len(t, sampler.samplers, 1) // Update the sampler with new sampling rates newSamplingRate := 0.2 newLowerBound := 3.0 newDefaultSamplingProbability := 0.1 newSamplingRates := []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: newSamplingRate}, }, { Operation: testFirstTimeOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: newSamplingRate}, }, } strategies = &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: newDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: newLowerBound, PerOperationStrategies: newSamplingRates, } sampler.update(strategies) assert.Equal(t, newLowerBound, sampler.lowerBound) assert.Equal(t, newDefaultSamplingProbability, sampler.defaultSampler.SamplingRate()) assert.Len(t, sampler.samplers, 2) } func TestMaxOperations(t *testing.T) { samplingRates := []*jaeger_api_v2.OperationSamplingStrategy{ { Operation: testOperationName, ProbabilisticSampling: &jaeger_api_v2.ProbabilisticSamplingStrategy{SamplingRate: 0.1}, }, } strategies := &jaeger_api_v2.PerOperationSamplingStrategies{ DefaultSamplingProbability: testDefaultSamplingProbability, DefaultLowerBoundTracesPerSecond: 2.0, PerOperationStrategies: samplingRates, } sampler := newPerOperationSampler(perOperationSamplerParams{ MaxOperations: 1, Strategies: strategies, }) result := sampler.ShouldSample(makeSamplingParameters(testMaxID-10, testFirstTimeOperationName)) assert.Equal(t, trace.RecordAndSample, result.Decision) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/jaegerremote/version.go000066400000000000000000000020141443314701600301330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package jaegerremote // import "go.opentelemetry.io/contrib/samplers/jaegerremote" // Version is the current release version of the Jaeger remote sampler. func Version() string { return "0.11.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/000077500000000000000000000000001443314701600257715ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/000077500000000000000000000000001443314701600301625ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/base2.go000066400000000000000000000043101443314701600315030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent" import "math" // These are IEEE 754 double-width floating point constants used with // math.Float64bits. const ( offsetExponentMask = 0x7ff0000000000000 offsetExponentBias = 1023 significandBits = 52 ) // expFromFloat64 returns floor(log2(x)). func expFromFloat64(x float64) int { return int((math.Float64bits(x)&offsetExponentMask)>>significandBits) - offsetExponentBias } // expToFloat64 returns 2^x. func expToFloat64(x int) float64 { return math.Float64frombits(uint64(offsetExponentBias+x) << significandBits) } // splitProb returns the two values of log-adjusted-count nearest to p // Example: // // splitProb(0.375) => (2, 1, 0.5) // // indicates to sample with probability (2^-2) 50% of the time // and (2^-1) 50% of the time. func splitProb(p float64) (uint8, uint8, float64) { if p < 2e-62 { // Note: spec. return pZeroValue, pZeroValue, 1 } // Take the exponent and drop the significand to locate the // smaller of two powers of two. exp := expFromFloat64(p) // Low is the smaller of two log-adjusted counts, the negative // of the exponent computed above. low := -exp // High is the greater of two log-adjusted counts (i.e., one // less than low, a smaller adjusted count means a larger // probability). high := low - 1 // Return these to probability values and use linear // interpolation to compute the required probability of // choosing the low-probability Sampler. lowP := expToFloat64(-low) highP := expToFloat64(-high) lowProb := (highP - p) / (highP - lowP) return uint8(low), uint8(high), lowProb } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/base2_test.go000066400000000000000000000032321443314701600325440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent import ( "testing" "github.com/stretchr/testify/require" ) func TestSplitProb(t *testing.T) { require.Equal(t, -1, expFromFloat64(0.6)) require.Equal(t, -2, expFromFloat64(0.4)) require.Equal(t, 0.5, expToFloat64(-1)) require.Equal(t, 0.25, expToFloat64(-2)) for _, tc := range []struct { in float64 low uint8 lowProb float64 }{ // Probability 0.75 corresponds with choosing S=1 (the // "low" probability) 50% of the time and S=0 (the // "high" probability) 50% of the time. {0.75, 1, 0.5}, {0.6, 1, 0.8}, {0.9, 1, 0.2}, // Powers of 2 exactly {1, 0, 1}, {0.5, 1, 1}, {0.25, 2, 1}, // Smaller numbers {0.05, 5, 0.4}, {0.1, 4, 0.4}, // 0.1 == 0.4 * 1/16 + 0.6 * 1/8 {0.003, 9, 0.464}, // Special cases: {0, 63, 1}, } { low, high, lowProb := splitProb(tc.in) require.Equal(t, tc.low, low, "got %v want %v", low, tc.low) if lowProb != 1 { require.Equal(t, tc.low-1, high, "got %v want %v", high, tc.low-1) } require.InEpsilon(t, tc.lowProb, lowProb, 1e-6, "got %v want %v", lowProb, tc.lowProb) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/go.mod000066400000000000000000000010621443314701600312670ustar00rootroot00000000000000module go.opentelemetry.io/contrib/samplers/probability/consistent go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/go.sum000066400000000000000000000042761443314701600313260ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/parent.go000066400000000000000000000050601443314701600320030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent" import ( "strings" "go.opentelemetry.io/otel" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) type ( parentProbabilitySampler struct { delegate sdktrace.Sampler } ) // ParentProbabilityBased is an implementation of the OpenTelemetry // Trace Sampler interface that provides additional checks for tracestate // Probability Sampling fields. func ParentProbabilityBased(root sdktrace.Sampler, samplers ...sdktrace.ParentBasedSamplerOption) sdktrace.Sampler { return &parentProbabilitySampler{ delegate: sdktrace.ParentBased(root, samplers...), } } // ShouldSample implements "go.opentelemetry.io/otel/sdk/trace".Sampler. func (p *parentProbabilitySampler) ShouldSample(params sdktrace.SamplingParameters) sdktrace.SamplingResult { psc := trace.SpanContextFromContext(params.ParentContext) // Note: We do not check psc.IsValid(), i.e., we repair the tracestate // with or without a parent TraceId and SpanId. state := psc.TraceState() otts, err := parseOTelTraceState(state.Get(traceStateKey), psc.IsSampled()) if err != nil { otel.Handle(err) value := otts.serialize() if len(value) > 0 { // Note: see the note in // "go.opentelemetry.io/otel/trace".TraceState.Insert(). The // error below is not a condition we're supposed to handle. state, _ = state.Insert(traceStateKey, value) } else { state = state.Delete(traceStateKey) } // Fix the broken tracestate before calling the delegate. params.ParentContext = trace.ContextWithSpanContext(params.ParentContext, psc.WithTraceState(state)) } return p.delegate.ShouldSample(params) } // Description returns the same description as the built-in // ParentBased sampler, with "ParentBased" replaced by // "ParentProbabilityBased". func (p *parentProbabilitySampler) Description() string { return "ParentProbabilityBased" + strings.TrimPrefix(p.delegate.Description(), "ParentBased") } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/parent_test.go000066400000000000000000000116051443314701600330440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent import ( "context" "strings" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) func TestParentSamplerDescription(t *testing.T) { opts := []sdktrace.ParentBasedSamplerOption{ sdktrace.WithRemoteParentNotSampled(sdktrace.AlwaysSample()), } root := ProbabilityBased(1) compare := sdktrace.ParentBased(root, opts...) parent := ParentProbabilityBased(root, opts...) require.Equal(t, strings.Replace( compare.Description(), "ParentBased", "ParentProbabilityBased", 1, ), parent.Description(), ) } func TestParentSamplerValidContext(t *testing.T) { parent := ParentProbabilityBased(sdktrace.NeverSample()) type testCase struct { in string sampled bool } for _, valid := range []testCase{ // sampled tests {"r:10", true}, {"r:10;a:b", true}, {"r:10;p:1", true}, {"r:10;p:10", true}, {"r:10;p:10;a:b", true}, {"r:10;p:63", true}, {"r:10;p:63;a:b", true}, {"p:0", true}, {"p:10;a:b", true}, {"p:63", true}, {"p:63;a:b", true}, // unsampled tests {"r:10", false}, {"r:10;a:b", false}, } { t.Run(testName(valid.in), func(t *testing.T) { traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736") spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7") traceState, err := trace.TraceState{}.Insert(traceStateKey, valid.in) require.NoError(t, err) sccfg := trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceState: traceState, } if valid.sampled { sccfg.TraceFlags = trace.FlagsSampled } parentCtx := trace.ContextWithSpanContext( context.Background(), trace.NewSpanContext(sccfg), ) result := parent.ShouldSample( sdktrace.SamplingParameters{ ParentContext: parentCtx, TraceID: traceID, Name: "test", Kind: trace.SpanKindServer, }, ) if valid.sampled { require.Equal(t, sdktrace.RecordAndSample, result.Decision) } else { require.Equal(t, sdktrace.Drop, result.Decision) } require.Equal(t, []attribute.KeyValue(nil), result.Attributes) require.Equal(t, valid.in, result.Tracestate.Get(traceStateKey)) }) } } func TestParentSamplerInvalidContext(t *testing.T) { parent := ParentProbabilityBased(sdktrace.NeverSample()) type testCase struct { in string sampled bool expect string } for _, invalid := range []testCase{ // sampled {"r:100", true, ""}, {"r:100;p:1", true, ""}, {"r:100;p:1;a:b", true, "a:b"}, {"r:10;p:100", true, "r:10"}, {"r:10;p:100;a:b", true, "r:10;a:b"}, // unsampled {"r:63;p:1", false, ""}, {"r:10;p:1", false, "r:10"}, {"r:10;p:1;a:b", false, "r:10;a:b"}, } { testInvalid := func(t *testing.T, isChildContext bool) { traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736") traceState, err := trace.TraceState{}.Insert(traceStateKey, invalid.in) require.NoError(t, err) sccfg := trace.SpanContextConfig{ TraceState: traceState, } if isChildContext { spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7") sccfg.TraceID = traceID sccfg.SpanID = spanID // Note: the other branch is testing a fabricated // situation where the context has a tracestate and // no TraceID. } if invalid.sampled { sccfg.TraceFlags = trace.FlagsSampled } parentCtx := trace.ContextWithSpanContext( context.Background(), trace.NewSpanContext(sccfg), ) result := parent.ShouldSample( sdktrace.SamplingParameters{ ParentContext: parentCtx, TraceID: sccfg.TraceID, Name: "test", Kind: trace.SpanKindServer, }, ) if isChildContext && invalid.sampled { require.Equal(t, sdktrace.RecordAndSample, result.Decision) } else { // if we're not a child context, ShouldSample // falls through to the delegate, which is NeverSample. require.Equal(t, sdktrace.Drop, result.Decision) } require.Equal(t, []attribute.KeyValue(nil), result.Attributes) require.Equal(t, invalid.expect, result.Tracestate.Get(traceStateKey)) } t.Run(testName(invalid.in)+"_with_parent", func(t *testing.T) { testInvalid(t, true) }) t.Run(testName(invalid.in)+"_no_parent", func(t *testing.T) { testInvalid(t, false) }) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/sampler.go000066400000000000000000000120541443314701600321560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package consistent provides a consistent probability based sampler. package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent" import ( "fmt" "math/bits" "math/rand" "sync" "go.opentelemetry.io/otel" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) type ( // ProbabilityBasedOption is an option to the // ConssitentProbabilityBased sampler. ProbabilityBasedOption interface { apply(*consistentProbabilityBasedConfig) } consistentProbabilityBasedConfig struct { source rand.Source } consistentProbabilityBasedRandomSource struct { rand.Source } consistentProbabilityBased struct { // "LAC" is an abbreviation for the logarithm of // adjusted count. Greater values have greater // representivity, therefore lesser sampling // probability. // lowLAC is the lower-probability log-adjusted count lowLAC uint8 // highLAC is the higher-probability log-adjusted // count. except for the zero probability special // case, highLAC == lowLAC - 1. highLAC uint8 // lowProb is the probability that lowLAC should be used, // in the interval (0, 1]. For exact powers of two and the // special case of 0 probability, lowProb == 1. lowProb float64 // lock protects rnd lock sync.Mutex rnd *rand.Rand } ) // WithRandomSource sets the source of the randomness used by the Sampler. func WithRandomSource(source rand.Source) ProbabilityBasedOption { return consistentProbabilityBasedRandomSource{source} } func (s consistentProbabilityBasedRandomSource) apply(cfg *consistentProbabilityBasedConfig) { cfg.source = s.Source } // ProbabilityBased samples a given fraction of traces. Based on the // OpenTelemetry specification, this Sampler supports only power-of-two // fractions. When the input fraction is not a power of two, it will // be rounded down. // - Fractions >= 1 will always sample. // - Fractions < 2^-62 are treated as zero. // // This Sampler sets the OpenTelemetry tracestate p-value and/or r-value. // // To respect the parent trace's `SampledFlag`, this sampler should be // used as the root delegate of a `Parent` sampler. func ProbabilityBased(fraction float64, opts ...ProbabilityBasedOption) sdktrace.Sampler { cfg := consistentProbabilityBasedConfig{ source: rand.NewSource(rand.Int63()), } for _, opt := range opts { opt.apply(&cfg) } if fraction < 0 { fraction = 0 } else if fraction > 1 { fraction = 1 } lowLAC, highLAC, lowProb := splitProb(fraction) return &consistentProbabilityBased{ lowLAC: lowLAC, highLAC: highLAC, lowProb: lowProb, rnd: rand.New(cfg.source), } } func (cs *consistentProbabilityBased) newR() uint8 { cs.lock.Lock() defer cs.lock.Unlock() return uint8(bits.LeadingZeros64(uint64(cs.rnd.Int63())) - 1) } func (cs *consistentProbabilityBased) lowChoice() bool { cs.lock.Lock() defer cs.lock.Unlock() return cs.rnd.Float64() < cs.lowProb } // ShouldSample implements "go.opentelemetry.io/otel/sdk/trace".Sampler. func (cs *consistentProbabilityBased) ShouldSample(p sdktrace.SamplingParameters) sdktrace.SamplingResult { psc := trace.SpanContextFromContext(p.ParentContext) // Note: this ignores whether psc.IsValid() because this // allows other otel trace state keys to pass through even // for root decisions. state := psc.TraceState() otts, err := parseOTelTraceState(state.Get(traceStateKey), psc.IsSampled()) if err != nil { // Note: a state.Insert(traceStateKey) // follows, nothing else needs to be done here. otel.Handle(err) } if !otts.hasRValue() { otts.rvalue = cs.newR() } var decision sdktrace.SamplingDecision var lac uint8 if cs.lowProb == 1 || cs.lowChoice() { lac = cs.lowLAC } else { lac = cs.highLAC } if lac <= otts.rvalue { decision = sdktrace.RecordAndSample otts.pvalue = lac } else { decision = sdktrace.Drop otts.pvalue = invalidValue } // Note: see the note in // "go.opentelemetry.io/otel/trace".TraceState.Insert(). The // error below is not a condition we're supposed to handle. state, _ = state.Insert(traceStateKey, otts.serialize()) return sdktrace.SamplingResult{ Decision: decision, Tracestate: state, } } // Description returns "ProbabilityBased{%g}" with the configured probability. func (cs *consistentProbabilityBased) Description() string { var prob float64 if cs.lowLAC != pZeroValue { prob = cs.lowProb * expToFloat64(-int(cs.lowLAC)) prob += (1 - cs.lowProb) * expToFloat64(-int(cs.highLAC)) } return fmt.Sprintf("ProbabilityBased{%g}", prob) } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/sampler_test.go000066400000000000000000000140251443314701600332150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent import ( "context" "fmt" "math/rand" "strings" "sync" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) type ( testDegrees int pValue int testErrorHandler struct { lock sync.Mutex errors []error } ) func parsePR(s string) (p, r string) { for _, kvf := range strings.Split(s, ";") { kv := strings.SplitN(kvf, ":", 2) switch kv[0] { case "p": p = kv[1] case "r": r = kv[1] } } return } func (eh *testErrorHandler) Handle(err error) { eh.lock.Lock() defer eh.lock.Unlock() eh.errors = append(eh.errors, err) } func (eh *testErrorHandler) Errors() []error { eh.lock.Lock() defer eh.lock.Unlock() return eh.errors } func TestSamplerDescription(t *testing.T) { const minProb = 0x1p-62 // 2.168404344971009e-19 for _, tc := range []struct { prob float64 expect string }{ {1, "ProbabilityBased{1}"}, {0, "ProbabilityBased{0}"}, {0.75, "ProbabilityBased{0.75}"}, {0.05, "ProbabilityBased{0.05}"}, {0.003, "ProbabilityBased{0.003}"}, {0.99999999, "ProbabilityBased{0.99999999}"}, {0.00000001, "ProbabilityBased{1e-08}"}, {minProb, "ProbabilityBased{2.168404344971009e-19}"}, {minProb * 1.5, "ProbabilityBased{3.2526065174565133e-19}"}, {3e-19, "ProbabilityBased{3e-19}"}, // out-of-range > 1 {1.01, "ProbabilityBased{1}"}, {101.1, "ProbabilityBased{1}"}, // out-of-range < 2^-62 {-1, "ProbabilityBased{0}"}, {-0.001, "ProbabilityBased{0}"}, {minProb * 0.999, "ProbabilityBased{0}"}, } { s := ProbabilityBased(tc.prob) require.Equal(t, tc.expect, s.Description(), "%#v", tc.prob) } } func getUnknowns(otts otelTraceState) string { otts.pvalue = invalidValue otts.rvalue = invalidValue return otts.serialize() } func TestSamplerBehavior(t *testing.T) { type testGroup struct { probability float64 minP uint8 maxP uint8 } type testCase struct { isRoot bool parentSampled bool ctxTracestate string hasErrors bool } for _, group := range []testGroup{ {1.0, 0, 0}, {0.75, 0, 1}, {0.5, 1, 1}, {0, 63, 63}, } { t.Run(fmt.Sprint(group.probability), func(t *testing.T) { for _, test := range []testCase{ // roots do not care if the context is // sampled, however preserve other // otel tracestate keys {true, false, "", false}, {true, false, "a:b", false}, // non-roots insert r {false, true, "", false}, {false, true, "a:b", false}, {false, false, "", false}, {false, false, "a:b", false}, // error cases: r-p inconsistency {false, true, "r:10;p:20", true}, {false, true, "r:10;p:20;a:b", true}, {false, false, "r:10;p:5", true}, {false, false, "r:10;p:5;a:b", true}, // error cases: out-of-range {false, false, "r:100", true}, {false, false, "r:100;a:b", true}, {false, true, "r:100;p:100", true}, {false, true, "r:100;p:100;a:b", true}, {false, true, "r:10;p:100", true}, {false, true, "r:10;p:100;a:b", true}, } { t.Run(testName(test.ctxTracestate), func(t *testing.T) { handler := &testErrorHandler{} otel.SetErrorHandler(handler) src := rand.NewSource(99999199999) sampler := ProbabilityBased(group.probability, WithRandomSource(src)) traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736") spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7") traceState := trace.TraceState{} if test.ctxTracestate != "" { var err error traceState, err = traceState.Insert(traceStateKey, test.ctxTracestate) require.NoError(t, err) } sccfg := trace.SpanContextConfig{ TraceState: traceState, } if !test.isRoot { sccfg.TraceID = traceID sccfg.SpanID = spanID } if test.parentSampled { sccfg.TraceFlags = trace.FlagsSampled } parentCtx := trace.ContextWithSpanContext( context.Background(), trace.NewSpanContext(sccfg), ) // Note: the error below is sometimes expected testState, _ := parseOTelTraceState(test.ctxTracestate, test.parentSampled) hasRValue := testState.hasRValue() const repeats = 10 for i := 0; i < repeats; i++ { result := sampler.ShouldSample( sdktrace.SamplingParameters{ ParentContext: parentCtx, TraceID: traceID, Name: "test", Kind: trace.SpanKindServer, }, ) sampled := result.Decision == sdktrace.RecordAndSample // The result is deterministically random. Parse the tracestate // to see that it is consistent. otts, err := parseOTelTraceState(result.Tracestate.Get(traceStateKey), sampled) require.NoError(t, err) require.True(t, otts.hasRValue()) require.Equal(t, []attribute.KeyValue(nil), result.Attributes) if otts.hasPValue() { require.LessOrEqual(t, group.minP, otts.pvalue) require.LessOrEqual(t, otts.pvalue, group.maxP) require.Equal(t, sdktrace.RecordAndSample, result.Decision) } else { require.Equal(t, sdktrace.Drop, result.Decision) } require.Equal(t, getUnknowns(testState), getUnknowns(otts)) if hasRValue { require.Equal(t, testState.rvalue, otts.rvalue) } if test.hasErrors { require.Less(t, 0, len(handler.Errors())) } else { require.Equal(t, 0, len(handler.Errors())) } } }) } }) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/statistical_test.go000066400000000000000000000216301443314701600340760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !race // +build !race package consistent import ( "context" "fmt" "math" "math/rand" "strconv" "testing" "time" "github.com/stretchr/testify/require" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" ) const ( oneDegree testDegrees = 1 twoDegrees testDegrees = 2 ) var ( trials = 20 populationSize = 1e5 // These may be computed using Gonum, e.g., // import "gonum.org/v1/gonum/stat/distuv" // with significance = 1 / float64(trials) = 0.05 // chiSquaredDF1 = distuv.ChiSquared{K: 1}.Quantile(significance) // chiSquaredDF2 = distuv.ChiSquared{K: 2}.Quantile(significance) // // These have been specified using significance = 0.05: chiSquaredDF1 = 0.003932140000019522 chiSquaredDF2 = 0.1025865887751011 chiSquaredByDF = [3]float64{ 0, chiSquaredDF1, chiSquaredDF2, } ) func TestSamplerStatistics(t *testing.T) { seedBankRng := rand.New(rand.NewSource(77777677777)) seedBank := make([]int64, 7) // N.B. Max=6 below. for i := range seedBank { seedBank[i] = seedBankRng.Int63() } type ( testCase struct { // prob is the sampling probability under test. prob float64 // upperP reflects the larger of the one or two // distinct adjusted counts represented in the test. // // For power-of-two tests, there is one distinct p-value, // and each span counts as 2**upperP representative spans. // // For non-power-of-two tests, there are two distinct // p-values expected, the test is specified using the // larger of these values corresponding with the // smaller sampling probability. The sampling // probability under test rounded down to the nearest // power of two is expected to equal 2**(-upperP). upperP pValue // degrees is 1 for power-of-two tests and 2 for // non-power-of-two tests. degrees testDegrees // seedIndex is the index into seedBank of the test seed. // If this is -1 the code below will search for the smallest // seed index that passes the test. seedIndex int } testResult struct { test testCase expected []float64 } ) var ( testSummary []testResult allTests = []testCase{ // Non-powers of two {0.90000, 1, twoDegrees, 3}, {0.60000, 1, twoDegrees, 2}, {0.33000, 2, twoDegrees, 2}, {0.13000, 3, twoDegrees, 1}, {0.10000, 4, twoDegrees, 0}, {0.05000, 5, twoDegrees, 0}, {0.01700, 6, twoDegrees, 2}, {0.01000, 7, twoDegrees, 2}, {0.00500, 8, twoDegrees, 2}, {0.00290, 9, twoDegrees, 4}, {0.00100, 10, twoDegrees, 6}, {0.00050, 11, twoDegrees, 0}, // Powers of two {0x1p-1, 1, oneDegree, 0}, {0x1p-4, 4, oneDegree, 0}, {0x1p-7, 7, oneDegree, 1}, } ) // Limit the test runtime by choosing 3 of the above // non-deterministically rand.New(rand.NewSource(time.Now().UnixNano())).Shuffle(len(allTests), func(i, j int) { allTests[i], allTests[j] = allTests[j], allTests[i] }) allTests = allTests[0:3] for _, test := range allTests { t.Run(fmt.Sprint(test.prob), func(t *testing.T) { var expected []float64 trySeedIndex := 0 for { var seed int64 seedIndex := test.seedIndex if seedIndex >= 0 { seed = seedBank[seedIndex] } else { seedIndex = trySeedIndex seed = seedBank[trySeedIndex] trySeedIndex++ } countFailures := func(src rand.Source) int { failed := 0 for j := 0; j < trials; j++ { var x float64 x, expected = sampleTrials(t, test.prob, test.degrees, test.upperP, src) if x < chiSquaredByDF[test.degrees] { failed++ } } return failed } failed := countFailures(rand.NewSource(seed)) if failed != 1 && test.seedIndex < 0 { t.Logf("%d probabilistic failures, trying a new seed for %g was 0x%x", failed, test.prob, seed) continue } else if failed != 1 { t.Errorf("wrong number of probabilistic failures for %g, should be 1 was %d for seed 0x%x", test.prob, failed, seed) } else if test.seedIndex < 0 { t.Logf("update the test for %g to use seed index %d", test.prob, seedIndex) t.Fail() return } else { // Note: this can be uncommented to verify that the preceding seed failed the test, // however this just doubles runtime and adds little evidence. For example: // if seedIndex != 0 && countFailures(rand.NewSource(seedBank[seedIndex-1])) == 1 { // t.Logf("update the test for %g to use seed index < %d", test.prob, seedIndex) // t.Fail() // } break } } testSummary = append(testSummary, testResult{ test: test, expected: expected, }) }) } // Note: This produces a table that should match what is in // the specification if it's the same test. for idx, res := range testSummary { var probability, pvalues, expectLower, expectUpper, expectUnsampled string if res.test.degrees == twoDegrees { probability = fmt.Sprintf("%.6f", res.test.prob) pvalues = fmt.Sprint(res.test.upperP-1, ", ", res.test.upperP) expectUnsampled = fmt.Sprintf("%.10g", res.expected[0]) expectLower = fmt.Sprintf("%.10g", res.expected[1]) expectUpper = fmt.Sprintf("%.10g", res.expected[2]) } else { probability = fmt.Sprintf("%x (%.6f)", res.test.prob, res.test.prob) pvalues = fmt.Sprint(res.test.upperP) expectUnsampled = fmt.Sprintf("%.10g", res.expected[0]) expectLower = fmt.Sprintf("%.10g", res.expected[1]) expectUpper = "n/a" } t.Logf("| %d | %s | %s | %s | %s | %s |\n", idx+1, probability, pvalues, expectLower, expectUpper, expectUnsampled) } } func sampleTrials(t *testing.T, prob float64, degrees testDegrees, upperP pValue, source rand.Source) (float64, []float64) { ctx := context.Background() sampler := ProbabilityBased( prob, WithRandomSource(source), ) recorder := &tracetest.InMemoryExporter{} provider := sdktrace.NewTracerProvider( sdktrace.WithSyncer(recorder), sdktrace.WithSampler(sampler), ) tracer := provider.Tracer("test") for i := 0; i < int(populationSize); i++ { _, span := tracer.Start(ctx, "span") span.End() } var minP, maxP pValue counts := map[pValue]int64{} for idx, r := range recorder.GetSpans() { ts := r.SpanContext.TraceState() p, _ := parsePR(ts.Get("ot")) pi, err := strconv.ParseUint(p, 10, 64) require.NoError(t, err) if idx == 0 { maxP = pValue(pi) minP = maxP } else { if pValue(pi) < minP { minP = pValue(pi) } if pValue(pi) > maxP { maxP = pValue(pi) } } counts[pValue(pi)]++ } require.Less(t, maxP, minP+pValue(degrees), "%v %v %v", minP, maxP, degrees) require.Less(t, maxP, pValue(63)) require.LessOrEqual(t, len(counts), 2) var ceilingProb, floorProb, floorChoice float64 // Note: we have to test len(counts) == 0 because this outcome // is actually possible, just very unlikely. If this happens // during development, a new initial seed must be used for // this test. // // The test specification ensures the test ensures there are // at least 20 expected items per category in these tests. require.NotEqual(t, 0, len(counts)) if degrees == 2 { // Note: because the test is probabilistic, we can't be // sure that both the min and max P values happen. We // can only assert that one of these is true. require.GreaterOrEqual(t, maxP, upperP-1) require.GreaterOrEqual(t, minP, upperP-1) require.LessOrEqual(t, maxP, upperP) require.LessOrEqual(t, minP, upperP) require.LessOrEqual(t, maxP-minP, 1) ceilingProb = 1 / float64(int64(1)<<(upperP-1)) floorProb = 1 / float64(int64(1)< !hasRValue() pvalue: invalidValue, // out-of-range => !hasPValue() } } func (otts otelTraceState) serialize() string { var sb strings.Builder semi := func() { if sb.Len() != 0 { _, _ = sb.WriteString(";") } } if otts.hasPValue() { _, _ = sb.WriteString(fmt.Sprintf("p:%d", otts.pvalue)) } if otts.hasRValue() { semi() _, _ = sb.WriteString(fmt.Sprintf("r:%d", otts.rvalue)) } for _, unk := range otts.unknown { ex := 0 if sb.Len() != 0 { ex = 1 } if sb.Len()+ex+len(unk) > traceStateSizeLimit { // Note: should this generate an explicit error? break } semi() _, _ = sb.WriteString(unk) } return sb.String() } func isValueByte(r byte) bool { if isLCAlphaNum(r) { return true } if isUCAlpha(r) { return true } return r == '.' || r == '_' || r == '-' } func isLCAlphaNum(r byte) bool { if isLCAlpha(r) { return true } return r >= '0' && r <= '9' } func isLCAlpha(r byte) bool { return r >= 'a' && r <= 'z' } func isUCAlpha(r byte) bool { return r >= 'A' && r <= 'Z' } func parseOTelTraceState(ts string, isSampled bool) (otelTraceState, error) { // nolint: revive var pval, rval string var unknown []string if len(ts) == 0 { return newTraceState(), nil } if len(ts) > traceStateSizeLimit { return newTraceState(), errTraceStateSyntax } for len(ts) > 0 { eqPos := 0 for ; eqPos < len(ts); eqPos++ { if eqPos == 0 { if isLCAlpha(ts[eqPos]) { continue } } else if isLCAlphaNum(ts[eqPos]) { continue } break } if eqPos == 0 || eqPos == len(ts) || ts[eqPos] != ':' { return newTraceState(), errTraceStateSyntax } key := ts[0:eqPos] tail := ts[eqPos+1:] sepPos := 0 for ; sepPos < len(tail); sepPos++ { if isValueByte(tail[sepPos]) { continue } break } if key == pValueSubkey { // Note: does the spec say how to handle duplicates? pval = tail[0:sepPos] } else if key == rValueSubkey { rval = tail[0:sepPos] } else { unknown = append(unknown, ts[0:sepPos+eqPos+1]) } if sepPos < len(tail) && tail[sepPos] != ';' { return newTraceState(), errTraceStateSyntax } if sepPos == len(tail) { break } ts = tail[sepPos+1:] // test for a trailing ; if ts == "" { return newTraceState(), errTraceStateSyntax } } otts := newTraceState() otts.unknown = unknown // Note: set R before P, so that P won't propagate if R has an error. value, err := parseNumber(rValueSubkey, rval, pZeroValue-1) if err != nil { return otts, err } otts.rvalue = value value, err = parseNumber(pValueSubkey, pval, pZeroValue) if err != nil { return otts, err } otts.pvalue = value // Invariant checking: unset P when the values are inconsistent. if otts.hasPValue() && otts.hasRValue() { implied := otts.pvalue <= otts.rvalue || otts.pvalue == pZeroValue if !isSampled || !implied { // Note: the error ensures the parent-based // sampler repairs the broken tracestate entry. otts.pvalue = invalidValue return otts, parseError(pValueSubkey, errTraceStateInconsistent) } } return otts, nil } func parseNumber(key string, input string, maximum uint8) (uint8, error) { if input == "" { return maximum + 1, nil } value, err := strconv.ParseUint(input, 10, 64) if err != nil { return maximum + 1, parseError(key, err) } if value > uint64(maximum) { return maximum + 1, parseError(key, strconv.ErrRange) } return uint8(value), nil } func parseError(key string, err error) error { return fmt.Errorf("otel tracestate: %s-value %w", key, err) } func (otts otelTraceState) hasRValue() bool { return otts.rvalue < pZeroValue } func (otts otelTraceState) hasPValue() bool { return otts.pvalue <= pZeroValue } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/tracestate_test.go000066400000000000000000000217431443314701600337160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent import ( "errors" "strconv" "strings" "testing" "github.com/stretchr/testify/require" ) func testName(in string) string { x := strings.NewReplacer(":", "_", ";", "_").Replace(in) if len(x) > 32 { return "" } return x } func TestNewTraceState(t *testing.T) { otts := newTraceState() require.False(t, otts.hasPValue()) require.False(t, otts.hasRValue()) require.Equal(t, "", otts.serialize()) } func TestTraceStatePRValueSerialize(t *testing.T) { otts := newTraceState() otts.pvalue = 3 otts.rvalue = 4 otts.unknown = []string{"a:b", "c:d"} require.True(t, otts.hasPValue()) require.True(t, otts.hasRValue()) require.Equal(t, "p:3;r:4;a:b;c:d", otts.serialize()) } func TestTraceStateSerializeOverflow(t *testing.T) { long := "x:" + strings.Repeat(".", 254) otts := newTraceState() otts.unknown = []string{long} // this drops the extra key, sorry! require.Equal(t, long, otts.serialize()) otts.pvalue = 1 require.Equal(t, "p:1", otts.serialize()) } func TestParseTraceStateUnsampled(t *testing.T) { type testCase struct { in string rval uint8 expectErr error } const notset = 255 for _, test := range []testCase{ // All are unsampled tests, i.e., `sampled` is not set in traceparent. {"r:2", 2, nil}, {"r:1;", notset, strconv.ErrSyntax}, {"r:1", 1, nil}, {"r:1=p:2", notset, strconv.ErrSyntax}, {"r:1;p:2=s:3", notset, strconv.ErrSyntax}, {":1;p:2=s:3", notset, strconv.ErrSyntax}, {":;p:2=s:3", notset, strconv.ErrSyntax}, {":;:", notset, strconv.ErrSyntax}, {":", notset, strconv.ErrSyntax}, {"", notset, nil}, {"r:;p=1", notset, strconv.ErrSyntax}, {"r:1", 1, nil}, {"r:10", 10, nil}, {"r:33", 33, nil}, {"r:61", 61, nil}, {"r:62", 62, nil}, // max r-value {"r:63", notset, strconv.ErrRange}, // out-of-range {"r:100", notset, strconv.ErrRange}, // out-of-range {"r:100001", notset, strconv.ErrRange}, // out-of-range {"p:64", notset, strconv.ErrRange}, {"p:100", notset, strconv.ErrRange}, {"r:1a", notset, strconv.ErrSyntax}, // not-hexadecimal {"p:-1", notset, strconv.ErrSyntax}, // non-negative // Inconsistent trace state: any p-value when unsampled {"p:4;r:2", 2, errTraceStateInconsistent}, {"p:1;r:2", 2, errTraceStateInconsistent}, } { t.Run(testName(test.in), func(t *testing.T) { // Note: passing isSampled=false as stated above. otts, err := parseOTelTraceState(test.in, false) require.False(t, otts.hasPValue(), "should have no p-value") if test.expectErr != nil { require.True(t, errors.Is(err, test.expectErr), "not expecting %v", err) } if test.rval != notset { require.True(t, otts.hasRValue()) require.Equal(t, test.rval, otts.rvalue) } else { require.False(t, otts.hasRValue(), "should have no r-value") } require.EqualValues(t, []string(nil), otts.unknown) if test.expectErr == nil { // Require serialize to round-trip otts2, err := parseOTelTraceState(otts.serialize(), false) require.NoError(t, err) require.Equal(t, otts, otts2) } }) } } func TestParseTraceStateSampled(t *testing.T) { type testCase struct { in string rval, pval uint8 expectErr error } const notset = 255 for _, test := range []testCase{ // All are sampled tests, i.e., `sampled` is set in traceparent. {"r:2;p:2", 2, 2, nil}, {"r:2;p:1", 2, 1, nil}, {"r:2;p:0", 2, 0, nil}, {"r:1;p:1", 1, 1, nil}, {"r:1;p:0", 1, 0, nil}, {"r:0;p:0", 0, 0, nil}, {"r:62;p:0", 62, 0, nil}, {"r:62;p:62", 62, 62, nil}, // The important special case: {"r:0;p:63", 0, 63, nil}, {"r:2;p:63", 2, 63, nil}, {"r:62;p:63", 62, 63, nil}, // Inconsistent p causes unset p-value. {"r:2;p:3", 2, notset, errTraceStateInconsistent}, {"r:2;p:4", 2, notset, errTraceStateInconsistent}, {"r:2;p:62", 2, notset, errTraceStateInconsistent}, {"r:0;p:1", 0, notset, errTraceStateInconsistent}, {"r:1;p:2", 1, notset, errTraceStateInconsistent}, {"r:61;p:62", 61, notset, errTraceStateInconsistent}, // Inconsistent r causes unset p-value and r-value. {"r:63;p:2", notset, notset, strconv.ErrRange}, {"r:120;p:2", notset, notset, strconv.ErrRange}, {"r:ab;p:2", notset, notset, strconv.ErrSyntax}, // Syntax is tested before range errors {"r:ab;p:77", notset, notset, strconv.ErrSyntax}, // p without r (when sampled) {"p:1", notset, 1, nil}, {"p:62", notset, 62, nil}, {"p:63", notset, 63, nil}, // r without p (when sampled) {"r:2", 2, notset, nil}, {"r:62", 62, notset, nil}, {"r:0", 0, notset, nil}, } { t.Run(testName(test.in), func(t *testing.T) { // Note: passing isSampled=true as stated above. otts, err := parseOTelTraceState(test.in, true) if test.expectErr != nil { require.True(t, errors.Is(err, test.expectErr), "not expecting %v", err) } else { require.NoError(t, err) } if test.pval != notset { require.True(t, otts.hasPValue()) require.Equal(t, test.pval, otts.pvalue) } else { require.False(t, otts.hasPValue(), "should have no p-value") } if test.rval != notset { require.True(t, otts.hasRValue()) require.Equal(t, test.rval, otts.rvalue) } else { require.False(t, otts.hasRValue(), "should have no r-value") } require.EqualValues(t, []string(nil), otts.unknown) if test.expectErr == nil { // Require serialize to round-trip otts2, err := parseOTelTraceState(otts.serialize(), true) require.NoError(t, err) require.Equal(t, otts, otts2) } }) } } func TestParseTraceStateExtra(t *testing.T) { type testCase struct { in string rval, pval uint8 sampled bool extra []string expectErr error } const notset = 255 for _, test := range []testCase{ // one field {"e100:1", notset, notset, false, []string{"e100:1"}, nil}, // two fields {"e1:1;e2:2", notset, notset, false, []string{"e1:1", "e2:2"}, nil}, {"e1:1;e2:2", notset, notset, false, []string{"e1:1", "e2:2"}, nil}, // one extra key, three ways {"r:2;p:2;extra:stuff", 2, 2, true, []string{"extra:stuff"}, nil}, {"extra:stuff;r:2;p:2", 2, 2, true, []string{"extra:stuff"}, nil}, {"p:2;extra:stuff;r:2", 2, 2, true, []string{"extra:stuff"}, nil}, // extra with inconsistent p with and without sampling {"r:3;extra:stuff;p:4", 3, notset, true, []string{"extra:stuff"}, errTraceStateInconsistent}, {"extra:stuff;r:3;p:2", 3, notset, false, []string{"extra:stuff"}, errTraceStateInconsistent}, // two extra fields {"e100:100;r:2;p:1;e101:101", 2, 1, true, []string{"e100:100", "e101:101"}, nil}, {"r:2;p:1;e100:100;e101:101", 2, 1, true, []string{"e100:100", "e101:101"}, nil}, {"e100:100;e101:101;r:2;p:1", 2, 1, true, []string{"e100:100", "e101:101"}, nil}, // parse error prevents capturing unrecognized keys {"1:1;u:V", notset, notset, true, nil, strconv.ErrSyntax}, {"X:1;u:V", notset, notset, true, nil, strconv.ErrSyntax}, {"x:1;u:V", notset, notset, true, []string{"x:1", "u:V"}, nil}, // no trailing ; {"x:1;", notset, notset, true, nil, strconv.ErrSyntax}, // empty key {"x:", notset, notset, true, []string{"x:"}, nil}, // charset test {"x:0X1FFF;y:.-_-.;z:", notset, notset, true, []string{"x:0X1FFF", "y:.-_-.", "z:"}, nil}, {"x1y2z3:1-2-3;y1:y_1;xy:-;r:50", 50, notset, true, []string{"x1y2z3:1-2-3", "y1:y_1", "xy:-"}, nil}, // size exceeded {"x:" + strings.Repeat("_", 255), notset, notset, false, nil, strconv.ErrSyntax}, {"x:" + strings.Repeat("_", 254), notset, notset, false, []string{"x:" + strings.Repeat("_", 254)}, nil}, } { t.Run(testName(test.in), func(t *testing.T) { // Note: These tests are independent of sampling state, // so both are tested. otts, err := parseOTelTraceState(test.in, test.sampled) if test.expectErr != nil { require.True(t, errors.Is(err, test.expectErr), "not expecting %v", err) } else { require.NoError(t, err) } if test.pval != notset { require.True(t, otts.hasPValue()) require.Equal(t, test.pval, otts.pvalue) } else { require.False(t, otts.hasPValue(), "should have no p-value") } if test.rval != notset { require.True(t, otts.hasRValue()) require.Equal(t, test.rval, otts.rvalue) } else { require.False(t, otts.hasRValue(), "should have no r-value") } require.EqualValues(t, test.extra, otts.unknown) // on success w/o r-value or p-value, serialize() should not modify if !otts.hasRValue() && !otts.hasPValue() && test.expectErr == nil { require.Equal(t, test.in, otts.serialize()) } }) } } open-telemetry-opentelemetry-go-contrib-2135499/samplers/probability/consistent/version.go000066400000000000000000000020401443314701600321720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent" // Version is the current release version of the consistent probability // sampler. func Version() string { return "0.11.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/tools/000077500000000000000000000000001443314701600227635ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/tools/go.mod000066400000000000000000000241771443314701600241040ustar00rootroot00000000000000module go.opentelemetry.io/contrib/tools go 1.19 exclude github.com/blizzy78/varnamelen v0.6.1 require ( github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.52.2 github.com/jcchavezs/porto v0.4.0 github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad go.opentelemetry.io/build-tools/crosslink v0.7.0 go.opentelemetry.io/build-tools/dbotconf v0.7.0 go.opentelemetry.io/build-tools/multimod v0.7.0 golang.org/x/tools v0.9.1 ) require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect github.com/Abirdcfly/dupword v0.0.11 // indirect github.com/Antonboom/errname v0.1.9 // indirect github.com/Antonboom/nilnil v0.1.3 // indirect github.com/BurntSushi/toml v1.2.1 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect github.com/OpenPeeDeeP/depguard v1.1.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/ashanbrown/forbidigo v1.5.1 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.0 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bombsimon/wsl/v3 v3.4.0 // indirect github.com/breml/bidichk v0.2.4 // indirect github.com/breml/errchkjson v0.3.1 // indirect github.com/butuzov/ireturn v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/daixiang0/gci v0.10.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/esimonov/ifshort v1.0.4 // indirect github.com/ettle/strcase v0.1.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/go-critic/go-critic v0.7.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect github.com/go-git/go-git/v5 v5.6.1 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.1.0 // indirect github.com/go-toolsmith/astfmt v1.1.0 // indirect github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect github.com/golangci/misspell v0.4.0 // indirect github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/julz/importas v0.1.0 // indirect github.com/junk1tm/musttag v0.5.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/kisielk/errcheck v1.6.3 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/kkHAIKE/contextcheck v1.1.4 // indirect github.com/kulti/thelper v0.6.3 // indirect github.com/kunwardeep/paralleltest v1.0.6 // indirect github.com/kyoh86/exportloopref v0.1.11 // indirect github.com/ldez/gomoddirectives v0.2.3 // indirect github.com/ldez/tagliatelle v0.4.0 // indirect github.com/leonklingele/grouper v1.1.1 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.1 // indirect github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect github.com/mgechev/revive v1.3.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moricho/tparallel v0.3.1 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/nishanths/exhaustive v0.9.5 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.9.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polyfloyd/go-errorlint v1.4.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quasilyte/go-ruleguard v0.3.19 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/ryancurrah/gomodguard v1.3.0 // indirect github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.23.0 // indirect github.com/securego/gosec/v2 v2.15.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/sivchari/containedctx v1.0.2 // indirect github.com/sivchari/nosnakecase v1.7.0 // indirect github.com/sivchari/tenv v1.7.1 // indirect github.com/skeema/knownhosts v1.1.0 // indirect github.com/sonatard/noctx v0.0.2 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.15.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/testify v1.8.3 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tdakkota/asciicheck v0.2.0 // indirect github.com/tetafro/godot v1.4.11 // indirect github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect github.com/timonwong/loggercheck v0.9.4 // indirect github.com/tomarrell/wrapcheck/v2 v2.8.1 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.0.3 // indirect github.com/ultraware/whitespace v0.0.5 // indirect github.com/uudashr/gocognit v1.0.6 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.2.0 // indirect gitlab.com/bosi/decorder v0.2.3 // indirect go.opentelemetry.io/build-tools v0.7.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.3 // indirect mvdan.cc/gofumpt v0.4.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/tools/go.sum000066400000000000000000003074631443314701600241330ustar00rootroot000000000000004d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= 4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= 4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= 4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Abirdcfly/dupword v0.0.11 h1:z6v8rMETchZXUIuHxYNmlUAuKuB21PeaSymTed16wgU= github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA= github.com/Antonboom/errname v0.1.9 h1:BZDX4r3l4TBZxZ2o2LNrlGxSHran4d1u4veZdoORTT4= github.com/Antonboom/errname v0.1.9/go.mod h1:nLTcJzevREuAsgTbG85UsuiWpMpAqbKD1HNZ29OzE58= github.com/Antonboom/nilnil v0.1.3 h1:6RTbx3d2mcEu3Zwq9TowQpQMVpP75zugwOtqY1RTtcE= github.com/Antonboom/nilnil v0.1.3/go.mod h1:iOov/7gRcXkeEU+EMGpBu2ORih3iyVEiWjeste1SJm8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 h1:+r1rSv4gvYn0wmRjC8X7IAzX8QezqtFV9m0MUHFJgts= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0/go.mod h1:b3g59n2Y+T5xmcxJL+UEG2f8cQploZm1mR/v6BW0mU0= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA= github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/ashanbrown/forbidigo v1.5.1 h1:WXhzLjOlnuDYPYQo/eFlcFMi8X/kLfvWLYu6CSoebis= github.com/ashanbrown/forbidigo v1.5.1/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU= github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= github.com/breml/bidichk v0.2.4 h1:i3yedFWWQ7YzjdZJHnPo9d/xURinSq3OM+gyM43K4/8= github.com/breml/bidichk v0.2.4/go.mod h1:7Zk0kRFt1LIZxtQdl9W9JwGAcLTTkOs+tN7wuEYGJ3s= github.com/breml/errchkjson v0.3.1 h1:hlIeXuspTyt8Y/UmP5qy1JocGNR00KQHgfaNtRAjoxQ= github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U= github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 h1:W9o46d2kbNL06lq7UNDPV0zYLzkrde/bjIqO02eoll0= github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.10.1 h1:eheNA3ljF6SxnPD/vE4lCBusVHmV3Rs3dkKvFrJ7MR0= github.com/daixiang0/gci v0.10.1/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-critic/go-critic v0.7.0 h1:tqbKzB8pqi0NsRZ+1pyU4aweAF7A7QN0Pi4Q02+rYnQ= github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw= github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY= github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= github.com/golangci/golangci-lint v1.52.2 h1:FrPElUUI5rrHXg1mQ7KxI1MXPAw5lBVskiz7U7a8a1A= github.com/golangci/golangci-lint v1.52.2/go.mod h1:S5fhC5sHM5kE22/HcATKd1XLWQxX+y7mHj8B5H91Q/0= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0= github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc= github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcchavezs/porto v0.4.0 h1:Zj7RligrxmDdKGo6fBO2xYAHxEgrVBfs1YAja20WbV4= github.com/jcchavezs/porto v0.4.0/go.mod h1:fESH0gzDHiutHRdX2hv27ojnOVFco37hg1W6E9EZF4A= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= github.com/junk1tm/musttag v0.5.0 h1:bV1DTdi38Hi4pG4OVWa7Kap0hi0o7EczuK6wQt9zPOM= github.com/junk1tm/musttag v0.5.0/go.mod h1:PcR7BA+oREQYvHwgjIDmw3exJeds5JzRcvEJTfjrA0M= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g= github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes= github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= github.com/ldez/tagliatelle v0.4.0 h1:sylp7d9kh6AdXN2DpVGHBRb5guTVAgOxqNGhbqc4b1c= github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I= github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgechev/revive v1.3.1 h1:OlQkcH40IB2cGuprTPcjB0iIUddgVZgGmDX3IAMR8D4= github.com/mgechev/revive v1.3.1/go.mod h1:YlD6TTWl2B8A103R9KWJSPVI9DrEf+oqr15q21Ld+5I= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME= github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.9.0 h1:Sm0zX5QfjJzkeCjEp+t6d3Ha0jwvoDjleP9XCsrEzOA= github.com/nunnatsa/ginkgolinter v0.9.0/go.mod h1:FHaMLURXP7qImeH6bvxWJUpyH+2tuqe5j4rW1gxJRmI= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.10.0 h1:znyI7l134wNg/wDktoVQPxPkgvhDfGCYUasey+h0rDQ= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polyfloyd/go-errorlint v1.4.0 h1:b+sQ5HibPIAjEZwtuwU8Wz/u0dMZ7YL+bk+9yWyHVJk= github.com/polyfloyd/go-errorlint v1.4.0/go.mod h1:qJCkPeBn+0EXkdKTrUCcuFStM2xrDKfxI3MGLXPexUs= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc= github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI= github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ= github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.23.0 h1:01h+/2Kd+NblNItNeux0veSL5cBF1jbEOPrEhDzGYq0= github.com/sashamelentyev/usestdlibvars v1.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU= github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw= github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYIc1yrHI= github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e h1:MV6KaVu/hzByHP0UvJ4HcMGE/8a6A4Rggc/0wx2AvJo= github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= github.com/tomarrell/wrapcheck/v2 v2.8.1 h1:HxSqDSN0sAt0yJYsrcYVoEeyM4aI9yAm3KQpIXDJRhQ= github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad h1:W0LEBv82YCGEtcmPA3uNZBI33/qF//HAAs3MawDjRa0= github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad/go.mod h1:Hy8o65+MXnS6EwGElrSRjUzQDLXreJlzYLlWiHtt8hM= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0= gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/build-tools v0.7.0 h1:46znGJz1mhkfzbno/O6bDk0VNgjaRdqF48GbAtkCiBg= go.opentelemetry.io/build-tools v0.7.0/go.mod h1:l38udQkILnLAzs9ucfDT24AAWJ7otdP6wtQXcyw/TeM= go.opentelemetry.io/build-tools/crosslink v0.7.0 h1:N7Cue57OJ+MtmBxN9HxJhy6L3xsMpBpXo/I+l76UpwY= go.opentelemetry.io/build-tools/crosslink v0.7.0/go.mod h1:4b21YR5+5/qwGmzOwIeTKoQayCX5tlnQKDal2POYZR8= go.opentelemetry.io/build-tools/dbotconf v0.7.0 h1:6EV61QuJGB5Xz0YyPC7V3yO+0ZGB3SLQPBq3fb1Y1mU= go.opentelemetry.io/build-tools/dbotconf v0.7.0/go.mod h1:7HqRvzmX+8wt8xy3zwSCSWufeT8gJiWhICpzNxn93yk= go.opentelemetry.io/build-tools/multimod v0.7.0 h1:Af1wVNaJRMVqRkiiRjeMrAfKJDejvpsLoBF9H5UrjSo= go.opentelemetry.io/build-tools/multimod v0.7.0/go.mod h1:WAwBtJC42JbRDzfi3erCYQ9M1RnyoIcqI/H8eqBBPQo= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 h1:J74nGeMgeFnYQJN59eFwh06jX/V8g0lB7LWpjSLxtgU= golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.4.3 h1:o/n5/K5gXqk8Gozvs2cnL0F2S1/g1vcGCAx2vETjITw= honnef.co/go/tools v0.4.3/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= open-telemetry-opentelemetry-go-contrib-2135499/tools/should_build.sh000077500000000000000000000022701443314701600260000ustar00rootroot00000000000000#!/bin/bash # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Returns 0 (true) when the current diff contains files in the provided # target directory. TARGET should be a unique package name in the directory # structure. For example, for the gocql integration, set TARGET=gocql so that # a diff in any of the files in the instrumentation/gocql/gocql directory # will be picked up by the grep. Diffs are compared against the main branch. TARGET=$1 if [ -z "$TARGET" ]; then echo "TARGET is undefined" exit 1 fi if git diff --name-only origin/main HEAD | grep -q "$TARGET"; then exit 0 else echo "no changes found for $TARGET. skipping tests..." exit 1 fi open-telemetry-opentelemetry-go-contrib-2135499/tools/tools.go000066400000000000000000000020421443314701600244500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build tools // +build tools package tools // import "go.opentelemetry.io/contrib/tools" import ( _ "github.com/client9/misspell/cmd/misspell" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "github.com/jcchavezs/porto/cmd/porto" _ "github.com/wadey/gocovmerge" _ "go.opentelemetry.io/build-tools/crosslink" _ "go.opentelemetry.io/build-tools/dbotconf" _ "go.opentelemetry.io/build-tools/multimod" _ "golang.org/x/tools/cmd/stringer" ) open-telemetry-opentelemetry-go-contrib-2135499/tools/version.go000066400000000000000000000017731443314701600250070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tools // import "go.opentelemetry.io/contrib/tools" // Version is the current release version of the OpenTelemetry Contrib tools. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/tools/wait.sh000077500000000000000000000032571443314701600242750ustar00rootroot00000000000000#!/bin/bash # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. wait_for_cassandra () { for ((i = 0; i < 5; ++i)); do if docker exec "$1" nodetool status | grep "^UN"; then exit 0 fi echo "Cassandra not yet available" sleep 10 done echo "Timeout waiting for cassandra to initialize" exit 1 } wait_for_mongo () { for ((i = 0; i < 5; ++i)); do if docker exec "$1" mongosh; then exit 0 fi echo "Mongo not yet available..." sleep 10 done echo "Timeout waiting for mongo to initialize" exit 1 } wait_for_gomemcache () { for ((i = 0; i < 5; ++i)); do if nc -z localhost 11211; then exit 0 fi echo "Gomemcache not yet available..." sleep 10 done echo "Timeout waiting for gomemcache to initialize" exit 1 } if [ -z "$CMD" ]; then echo "CMD is undefined. exiting..." exit 1 elif [ -z "$IMG_NAME" ]; then echo "IMG_NAME is undefined. exiting..." exit 1 fi if [ "$CMD" == "cassandra" ]; then wait_for_cassandra "$IMG_NAME" elif [ "$CMD" == "mongo" ]; then wait_for_mongo "$IMG_NAME" elif [ "$CMD" == "gomemcache" ]; then wait_for_gomemcache else echo "unknown CMD" exit 1 fi open-telemetry-opentelemetry-go-contrib-2135499/version.go000066400000000000000000000021501443314701600236350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package contrib contains common values used across all // instrumentation, exporter, and detector contributions. package contrib // import "go.opentelemetry.io/contrib" // Version is the current release version of OpenTelemetry Contrib in use. func Version() string { return "1.17.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() } open-telemetry-opentelemetry-go-contrib-2135499/versions.yaml000066400000000000000000000150201443314701600243550ustar00rootroot00000000000000# Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module-sets: stable-v1: version: v1.17.0 modules: - go.opentelemetry.io/contrib - go.opentelemetry.io/contrib/tools - go.opentelemetry.io/contrib/propagators/aws - go.opentelemetry.io/contrib/propagators/ot - go.opentelemetry.io/contrib/propagators/jaeger - go.opentelemetry.io/contrib/propagators/b3 - go.opentelemetry.io/contrib/detectors/gcp - go.opentelemetry.io/contrib/detectors/aws/ec2 - go.opentelemetry.io/contrib/detectors/aws/ecs - go.opentelemetry.io/contrib/detectors/aws/eks experimental-instrumentation: version: v0.42.0 modules: - go.opentelemetry.io/contrib/detectors/aws/lambda - go.opentelemetry.io/contrib/propagators/autoprop - go.opentelemetry.io/contrib/propagators/opencensus - go.opentelemetry.io/contrib/propagators/opencensus/examples - go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron - go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/example - go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron/test - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/example - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/test - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/example - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/test - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/test - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/example - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux/test - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/example - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin/test - go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho - go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/example - go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho/test - go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama - go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/example - go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama/test - go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit - go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/example - go.opentelemetry.io/contrib/instrumentation/github.com/go-kit/kit/otelkit/test - go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql - go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/example - go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/test - go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego - go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/example - go.opentelemetry.io/contrib/instrumentation/github.com/astaxie/beego/otelbeego/test - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/example - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/test - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/example - go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws/test - go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache - go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/example - go.opentelemetry.io/contrib/instrumentation/github.com/bradfitz/gomemcache/memcache/otelmemcache/test - go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful - go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/example - go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/test - go.opentelemetry.io/contrib/zpages experimental-metrics: version: v0.42.0 modules: - go.opentelemetry.io/contrib/instrumentation/host - go.opentelemetry.io/contrib/instrumentation/host/example - go.opentelemetry.io/contrib/instrumentation/runtime - go.opentelemetry.io/contrib/instrumentation/runtime/example experimental-samplers: version: v0.11.0 modules: - go.opentelemetry.io/contrib/samplers/aws/xray - go.opentelemetry.io/contrib/samplers/jaegerremote - go.opentelemetry.io/contrib/samplers/jaegerremote/example - go.opentelemetry.io/contrib/samplers/probability/consistent excluded-modules: - go.opentelemetry.io/contrib/instrgen - go.opentelemetry.io/contrib/instrgen/driver - go.opentelemetry.io/contrib/instrgen/testdata/interface open-telemetry-opentelemetry-go-contrib-2135499/zpages/000077500000000000000000000000001443314701600231145ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/zpages/boundaries.go000066400000000000000000000033161443314701600256010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages // import "go.opentelemetry.io/contrib/zpages" import ( "sort" "time" ) const zeroDuration = time.Duration(0) const maxDuration = time.Duration(1<<63 - 1) var defaultBoundaries = newBoundaries([]time.Duration{ 10 * time.Microsecond, 100 * time.Microsecond, time.Millisecond, 10 * time.Millisecond, 100 * time.Millisecond, time.Second, 10 * time.Second, 100 * time.Second, }) // boundaries represents the interval bounds for the latency based samples. type boundaries struct { durations []time.Duration } // newBoundaries returns a new boundaries. func newBoundaries(durations []time.Duration) *boundaries { sort.Slice(durations, func(i, j int) bool { return durations[i] < durations[j] }) return &boundaries{durations: durations} } // numBuckets returns the number of buckets needed for these boundaries. func (lb boundaries) numBuckets() int { return len(lb.durations) + 1 } // getBucketIndex returns the appropriate bucket index for a given latency. func (lb boundaries) getBucketIndex(latency time.Duration) int { i := 0 for i < len(lb.durations) && latency >= lb.durations[i] { i++ } return i } open-telemetry-opentelemetry-go-contrib-2135499/zpages/boundaries_test.go000066400000000000000000000032261443314701600266400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages import ( "testing" "time" "github.com/stretchr/testify/assert" ) var testDurations = []time.Duration{1 * time.Second} func TestBoundariesNumBuckets(t *testing.T) { assert.Equal(t, 1, newBoundaries(nil).numBuckets()) assert.Equal(t, 1, newBoundaries([]time.Duration{}).numBuckets()) assert.Equal(t, 2, newBoundaries(testDurations).numBuckets()) assert.Equal(t, 9, defaultBoundaries.numBuckets()) } func TestBoundariesGetBucketIndex(t *testing.T) { assert.Equal(t, 0, newBoundaries(testDurations).getBucketIndex(zeroDuration)) assert.Equal(t, 0, newBoundaries(testDurations).getBucketIndex(500*time.Millisecond)) assert.Equal(t, 1, newBoundaries(testDurations).getBucketIndex(1500*time.Millisecond)) assert.Equal(t, 0, newBoundaries(testDurations).getBucketIndex(zeroDuration)) assert.Equal(t, 0, defaultBoundaries.getBucketIndex(zeroDuration)) assert.Equal(t, 3, defaultBoundaries.getBucketIndex(5*time.Millisecond)) assert.Equal(t, 6, defaultBoundaries.getBucketIndex(5*time.Second)) assert.Equal(t, 8, defaultBoundaries.getBucketIndex(maxDuration)) } open-telemetry-opentelemetry-go-contrib-2135499/zpages/bucket.go000066400000000000000000000043351443314701600247250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2017, OpenCensus Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages // import "go.opentelemetry.io/contrib/zpages" import ( "time" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) const ( // defaultBucketCapacity is the default capacity for every bucket (latency or error based). defaultBucketCapacity = 10 // samplePeriod is the minimum time between accepting spans in a single bucket. samplePeriod = time.Second ) // bucket is a container for a set of spans for latency buckets or errored spans. type bucket struct { nextTime time.Time // next time we can accept a span buffer []sdktrace.ReadOnlySpan // circular buffer of spans nextIndex int // location next ReadOnlySpan should be placed in buffer overflow bool // whether the circular buffer has wrapped around } // newBucket returns a new bucket with the given capacity. func newBucket(capacity uint) *bucket { return &bucket{ buffer: make([]sdktrace.ReadOnlySpan, capacity), } } // add adds a span to the bucket, if nextTime has been reached. func (b *bucket) add(s sdktrace.ReadOnlySpan) { if s.EndTime().Before(b.nextTime) { return } if len(b.buffer) == 0 { return } b.nextTime = s.EndTime().Add(samplePeriod) b.buffer[b.nextIndex] = s b.nextIndex++ if b.nextIndex == len(b.buffer) { b.nextIndex = 0 b.overflow = true } } // len returns the number of spans in the bucket. func (b *bucket) len() int { if b.overflow { return len(b.buffer) } return b.nextIndex } // spans returns the spans in this bucket. func (b *bucket) spans() []sdktrace.ReadOnlySpan { return append([]sdktrace.ReadOnlySpan(nil), b.buffer[0:b.len()]...) } open-telemetry-opentelemetry-go-contrib-2135499/zpages/bucket_test.go000066400000000000000000000054071443314701600257650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages import ( "testing" "time" "github.com/stretchr/testify/assert" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) type testSpan struct { sdktrace.ReadWriteSpan spanContext trace.SpanContext name string startTime time.Time endTime time.Time status sdktrace.Status } func (ts *testSpan) SpanContext() trace.SpanContext { return ts.spanContext } func (ts *testSpan) Status() sdktrace.Status { return ts.status } func (ts *testSpan) Name() string { return ts.name } func (ts *testSpan) StartTime() time.Time { return ts.startTime } func (ts *testSpan) EndTime() time.Time { return ts.endTime } func TestBucket(t *testing.T) { bkt := newBucket(defaultBucketCapacity) assert.Equal(t, 0, bkt.len()) for i := 1; i <= defaultBucketCapacity; i++ { bkt.add(&testSpan{endTime: time.Unix(int64(i), 0)}) assert.Equal(t, i, bkt.len()) spans := bkt.spans() assert.Len(t, spans, i) for j := 0; j < i; j++ { assert.Equal(t, time.Unix(int64(j+1), 0), spans[j].EndTime()) } } for i := defaultBucketCapacity + 1; i <= 2*defaultBucketCapacity; i++ { bkt.add(&testSpan{endTime: time.Unix(int64(i), 0)}) assert.Equal(t, defaultBucketCapacity, bkt.len()) spans := bkt.spans() assert.Len(t, spans, defaultBucketCapacity) // First spans will have newer times, and will replace older timestamps. for j := 0; j < i-defaultBucketCapacity; j++ { assert.Equal(t, time.Unix(int64(j+defaultBucketCapacity+1), 0), spans[j].EndTime()) } for j := i - defaultBucketCapacity; j < defaultBucketCapacity; j++ { assert.Equal(t, time.Unix(int64(j+1), 0), spans[j].EndTime()) } } } func TestBucketAddSample(t *testing.T) { bkt := newBucket(defaultBucketCapacity) assert.Equal(t, 0, bkt.len()) for i := 0; i < 1000; i++ { bkt.add(&testSpan{endTime: time.Unix(1, int64(i*1000))}) assert.Equal(t, 1, bkt.len()) spans := bkt.spans() assert.Len(t, spans, 1) assert.Equal(t, time.Unix(1, 0), spans[0].EndTime()) } } func TestBucketZeroCapacity(t *testing.T) { bkt := newBucket(0) assert.Equal(t, 0, bkt.len()) bkt.add(&testSpan{endTime: time.Unix(1, 0)}) assert.Equal(t, 0, bkt.len()) assert.Len(t, bkt.spans(), 0) } open-telemetry-opentelemetry-go-contrib-2135499/zpages/go.mod000066400000000000000000000010311443314701600242150ustar00rootroot00000000000000module go.opentelemetry.io/contrib/zpages go 1.19 require ( github.com/stretchr/testify v1.8.3 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect golang.org/x/sys v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) open-telemetry-opentelemetry-go-contrib-2135499/zpages/go.sum000066400000000000000000000042761443314701600242600ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/000077500000000000000000000000001443314701600247305ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/gen.go000066400000000000000000000013361443314701600260330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package internal // import "go.opentelemetry.io/contrib/zpages/internal" import "embed" //go:embed templates/* var Templates embed.FS open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/templates/000077500000000000000000000000001443314701600267265ustar00rootroot00000000000000open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/templates/footer.html000066400000000000000000000000201443314701600311020ustar00rootroot00000000000000 open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/templates/header.html000066400000000000000000000007371443314701600310530ustar00rootroot00000000000000 {{.Title}}

{{.Title}}

open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/templates/summary.html000066400000000000000000000031371443314701600313150ustar00rootroot00000000000000 {{range .LatencyBucketNames}}{{end}} {{$a := .TracesEndpoint}} {{$links := .Links}} {{range $rowindex, $row := .Rows}} {{- $name := .Name}} {{- if even $rowindex}}{{else}}{{end -}} {{- if $links -}} {{- else -}} {{- end -}} {{- if $links -}} {{range $index, $value := .Latency}}{{end}} {{- else -}} {{range .Latency}}{{end}} {{- end -}} {{- if $links -}} {{- else -}} {{- end -}} {{end}}
Span Name   |  Running   |   Latency Samples   |   Error Samples
  |     |  [{{.}}]  |  
{{.Name}}  |  {{.Active}}{{.Active}}  |  {{$value}}{{.}}  |  {{.Errors}}{{.Errors}}
open-telemetry-opentelemetry-go-contrib-2135499/zpages/internal/templates/traces.html000066400000000000000000000006441443314701600311010ustar00rootroot00000000000000

Span Name: {{.Name}}

{{.Num}} Requests

When                       Elapsed (sec)
----------------------------------------
{{range .Rows}}{{printf "%26s" (index .Fields 0)}} {{printf "%12s" (index .Fields 1)}} {{index .Fields 2}}{{.|spanRow}}
{{end}}

TraceId means sampled request. TraceId means not sampled request.

open-telemetry-opentelemetry-go-contrib-2135499/zpages/spanprocessor.go000066400000000000000000000143651443314701600263550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2017, OpenCensus Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages // import "go.opentelemetry.io/contrib/zpages" import ( "context" "sync" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) var _ sdktrace.SpanProcessor = (*SpanProcessor)(nil) // perMethodSummary is a summary of the spans stored for a single span name. type perMethodSummary struct { activeSpans int latencySpans []int errorSpans int } // SpanProcessor is an sdktrace.SpanProcessor implementation that exposes zpages functionality for opentelemetry-go. // // It tracks all active spans, and stores samples of spans based on latency for non errored spans, // and samples for errored spans. type SpanProcessor struct { // Cannot keep track of the active Spans per name because the Span interface, // allows the name to be changed, and that will leak memory. activeSpansStore sync.Map spanSampleStores sync.Map } // NewSpanProcessor returns a new SpanProcessor. func NewSpanProcessor() *SpanProcessor { return &SpanProcessor{} } // OnStart adds span as active and reports it with zpages. func (ssm *SpanProcessor) OnStart(_ context.Context, span sdktrace.ReadWriteSpan) { sc := span.SpanContext() if sc.IsValid() { ssm.activeSpansStore.Store(spanKey(sc), span) } } // OnEnd processes all spans and reports them with zpages. func (ssm *SpanProcessor) OnEnd(span sdktrace.ReadOnlySpan) { sc := span.SpanContext() if sc.IsValid() { ssm.activeSpansStore.Delete(spanKey(sc)) } name := span.Name() value, ok := ssm.spanSampleStores.Load(name) if !ok { value, _ = ssm.spanSampleStores.LoadOrStore(name, newSampleStore(defaultBucketCapacity, defaultBucketCapacity)) } value.(*sampleStore).sampleSpan(span) } // Shutdown does nothing. func (ssm *SpanProcessor) Shutdown(context.Context) error { // Do nothing return nil } // ForceFlush does nothing. func (ssm *SpanProcessor) ForceFlush(context.Context) error { // Do nothing return nil } // spanStoreForName returns the sampleStore for the given name. // // It returns nil if it doesn't exist. func (ssm *SpanProcessor) spanStoreForName(name string) *sampleStore { if value, ok := ssm.spanSampleStores.Load(name); ok { return value.(*sampleStore) } return nil } // spansPerMethod returns a summary of what spans are being stored for each span name. func (ssm *SpanProcessor) spansPerMethod() map[string]*perMethodSummary { out := make(map[string]*perMethodSummary) ssm.spanSampleStores.Range(func(name, s interface{}) bool { out[name.(string)] = s.(*sampleStore).perMethodSummary() return true }) ssm.activeSpansStore.Range(func(_, sp interface{}) bool { span := sp.(sdktrace.ReadOnlySpan) if pms, ok := out[span.Name()]; ok { pms.activeSpans++ return true } out[span.Name()] = &perMethodSummary{activeSpans: 1} return true }) return out } // activeSpans returns the active spans for the given name. func (ssm *SpanProcessor) activeSpans(name string) []sdktrace.ReadOnlySpan { var out []sdktrace.ReadOnlySpan ssm.activeSpansStore.Range(func(_, sp interface{}) bool { span := sp.(sdktrace.ReadOnlySpan) if span.Name() == name { out = append(out, span) } return true }) return out } // errorSpans returns a sample of error spans. func (ssm *SpanProcessor) errorSpans(name string) []sdktrace.ReadOnlySpan { s := ssm.spanStoreForName(name) if s == nil { return nil } return s.errorSpans() } // spansByLatency returns a sample of successful spans. // // minLatency is the minimum latency of spans to be returned. // maxDuration, if nonzero, is the maximum latency of spans to be returned. func (ssm *SpanProcessor) spansByLatency(name string, latencyBucketIndex int) []sdktrace.ReadOnlySpan { s := ssm.spanStoreForName(name) if s == nil { return nil } return s.spansByLatency(latencyBucketIndex) } // sampleStore stores a sampled of spans for a particular span name. // // It contains sample of spans for error requests (status code is codes.Error); // and a sample of spans for successful requests, bucketed by latency. type sampleStore struct { sync.Mutex // protects everything below. latency []*bucket errors *bucket } // newSampleStore creates a sampleStore. func newSampleStore(latencyBucketSize uint, errorBucketSize uint) *sampleStore { s := &sampleStore{ latency: make([]*bucket, defaultBoundaries.numBuckets()), errors: newBucket(errorBucketSize), } for i := range s.latency { s.latency[i] = newBucket(latencyBucketSize) } return s } func (ss *sampleStore) perMethodSummary() *perMethodSummary { ss.Lock() defer ss.Unlock() p := &perMethodSummary{} p.errorSpans = ss.errors.len() for _, b := range ss.latency { p.latencySpans = append(p.latencySpans, b.len()) } return p } func (ss *sampleStore) spansByLatency(latencyBucketIndex int) []sdktrace.ReadOnlySpan { ss.Lock() defer ss.Unlock() if latencyBucketIndex < 0 || latencyBucketIndex >= len(ss.latency) { return nil } return ss.latency[latencyBucketIndex].spans() } func (ss *sampleStore) errorSpans() []sdktrace.ReadOnlySpan { ss.Lock() defer ss.Unlock() return ss.errors.spans() } // sampleSpan removes adds to the corresponding latency or error bucket. func (ss *sampleStore) sampleSpan(span sdktrace.ReadOnlySpan) { code := span.Status().Code ss.Lock() defer ss.Unlock() if code == codes.Error { ss.errors.add(span) return } latency := span.EndTime().Sub(span.StartTime()) // In case of time skew or wrong time, sample as 0 latency. if latency < 0 { latency = 0 } ss.latency[defaultBoundaries.getBucketIndex(latency)].add(span) } func spanKey(sc trace.SpanContext) [24]byte { var sk [24]byte tid := sc.TraceID() copy(sk[0:16], tid[:]) sid := sc.SpanID() copy(sk[16:24], sid[:]) return sk } open-telemetry-opentelemetry-go-contrib-2135499/zpages/spanprocessor_test.go000066400000000000000000000155341443314701600274130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages import ( "context" "reflect" "sort" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) func TestSpanProcessorDoNothing(t *testing.T) { zsp := NewSpanProcessor() assert.NoError(t, zsp.ForceFlush(context.Background())) assert.NoError(t, zsp.Shutdown(context.Background())) } func TestSpanProcessor(t *testing.T) { zsp := NewSpanProcessor() tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSpanProcessor(zsp), ) const spanName = "testSpan" const numSpans = 9 tracer := tracerProvider.Tracer("test") spans := createActiveSpans(tracer, spanName, numSpans) // Sort the spans by the address pointer so we can compare. sort.Slice(spans, func(i, j int) bool { return reflect.ValueOf(spans[i]).Pointer() < reflect.ValueOf(spans[j]).Pointer() }) require.Len(t, spans, numSpans) activeSpans := zsp.activeSpans(spanName) assert.Len(t, activeSpans, numSpans) // Sort the activeSpans by the address pointer so we can compare. sort.Slice(activeSpans, func(i, j int) bool { return reflect.ValueOf(activeSpans[i]).Pointer() < reflect.ValueOf(activeSpans[j]).Pointer() }) for i := range spans { assert.Same(t, spans[i], activeSpans[i]) } // No ended spans so there will be no error, no latency samples. assert.Len(t, zsp.errorSpans(spanName), 0) for i := 0; i < defaultBoundaries.numBuckets(); i++ { assert.Len(t, zsp.spansByLatency(spanName, i), 0) } spansPM := zsp.spansPerMethod() require.Equal(t, 1, len(spansPM)) assert.Equal(t, numSpans, spansPM[spanName].activeSpans) // End all Spans, they will end pretty fast, so we can only check that we have at least one in // errors and one in latency samples. for _, s := range spans { s.End() } // Test that no more active spans. assert.Len(t, zsp.activeSpans(spanName), 0) assert.LessOrEqual(t, 1, len(zsp.errorSpans(spanName))) numLatencySamples := 0 for i := 0; i < defaultBoundaries.numBuckets(); i++ { numLatencySamples += len(zsp.spansByLatency(spanName, i)) } assert.LessOrEqual(t, 1, numLatencySamples) } func TestSpanProcessorFuzzer(t *testing.T) { zsp := NewSpanProcessor() tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSpanProcessor(zsp), ) const numIterations = 200 const numSpansPerIteration = 90 var wg sync.WaitGroup wg.Add(4) go func() { for i := 0; i < numIterations; i++ { assert.LessOrEqual(t, 0, len(zsp.spansPerMethod())) assert.GreaterOrEqual(t, 2, len(zsp.spansPerMethod())) createEndedSpans(tracerProvider.Tracer("test1"), "testSpan1", numSpansPerIteration) // Call for spans names created by the other goroutines. assert.LessOrEqual(t, 0, len(zsp.activeSpans("testSpan2"))) assert.LessOrEqual(t, 0, len(zsp.errorSpans("testSpan2"))) assert.LessOrEqual(t, 0, len(zsp.spansByLatency("testSpan2", 1))) } wg.Done() }() go func() { for i := 0; i < numIterations; i++ { assert.LessOrEqual(t, 0, len(zsp.spansPerMethod())) assert.GreaterOrEqual(t, 2, len(zsp.spansPerMethod())) createEndedSpans(tracerProvider.Tracer("test2"), "testSpan2", numSpansPerIteration) // Call for spans names created by the other goroutines. assert.LessOrEqual(t, 0, len(zsp.activeSpans("testSpan1"))) assert.LessOrEqual(t, 0, len(zsp.errorSpans("testSpan1"))) assert.LessOrEqual(t, 0, len(zsp.spansByLatency("testSpan1", 1))) } wg.Done() }() go func() { for i := 0; i < numIterations; i++ { assert.LessOrEqual(t, 0, len(zsp.spansPerMethod())) assert.GreaterOrEqual(t, 2, len(zsp.spansPerMethod())) createEndedSpans(tracerProvider.Tracer("test3"), "testSpan1", numSpansPerIteration) // Call for spans names created by the other goroutines. assert.LessOrEqual(t, 0, len(zsp.activeSpans("testSpan2"))) assert.LessOrEqual(t, 0, len(zsp.errorSpans("testSpan2"))) assert.LessOrEqual(t, 0, len(zsp.spansByLatency("testSpan2", 1))) } wg.Done() }() go func() { for i := 0; i < numIterations; i++ { assert.LessOrEqual(t, 0, len(zsp.spansPerMethod())) assert.GreaterOrEqual(t, 2, len(zsp.spansPerMethod())) createEndedSpans(tracerProvider.Tracer("test4"), "testSpan2", numSpansPerIteration) // Call for spans names created by the other goroutines. assert.LessOrEqual(t, 0, len(zsp.activeSpans("testSpan1"))) assert.LessOrEqual(t, 0, len(zsp.errorSpans("testSpan1"))) assert.LessOrEqual(t, 0, len(zsp.spansByLatency("testSpan1", 1))) } wg.Done() }() wg.Wait() } func TestSpanProcessorNegativeLatency(t *testing.T) { zsp := NewSpanProcessor() ts := &testSpan{ spanContext: trace.NewSpanContext(trace.SpanContextConfig{ TraceID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}, SpanID: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, TraceFlags: 1, Remote: false, }), name: "test", startTime: time.Unix(10, 0), endTime: time.Unix(5, 0), status: sdktrace.Status{ Code: codes.Ok, Description: "", }, } zsp.OnStart(context.Background(), ts) spansPM := zsp.spansPerMethod() require.Equal(t, 1, len(spansPM)) assert.Equal(t, 1, spansPM["test"].activeSpans) zsp.OnEnd(ts) spansPM = zsp.spansPerMethod() require.Equal(t, 1, len(spansPM)) assert.Equal(t, 1, spansPM["test"].latencySpans[0]) } func TestSpanProcessorSpansByLatencyWrongIndex(t *testing.T) { zsp := NewSpanProcessor() tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSpanProcessor(zsp), ) tracer := tracerProvider.Tracer("test") createEndedSpans(tracer, "test", 6) assert.Nil(t, zsp.spansByLatency("test", -1)) assert.Nil(t, zsp.spansByLatency("test", defaultBoundaries.numBuckets())) } func createEndedSpans(tracer trace.Tracer, spanName string, numSpans int) { for i := 0; i < numSpans; i++ { _, span := tracer.Start(context.Background(), spanName) span.SetStatus(codes.Code(i%3), "") span.End() } } func createActiveSpans(tracer trace.Tracer, spanName string, numSpans int) []trace.Span { var spans []trace.Span for i := 0; i < numSpans; i++ { _, span := tracer.Start(context.Background(), spanName) span.SetStatus(codes.Code(i%3), "") spans = append(spans, span) } return spans } open-telemetry-opentelemetry-go-contrib-2135499/zpages/templates.go000066400000000000000000000044721443314701600254500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2017, OpenCensus Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package zpages // import "go.opentelemetry.io/contrib/zpages" import ( "fmt" "html/template" "io" "log" "go.opentelemetry.io/contrib/zpages/internal" ) var ( templateFunctions = template.FuncMap{ "even": even, "spanRow": spanRowFormatter, } headerTemplate = parseTemplate("header") summaryTableTemplate = parseTemplate("summary") tracesTableTemplate = parseTemplate("traces") footerTemplate = parseTemplate("footer") ) // headerData contains data for the header template. type headerData struct { Title string } func parseTemplate(name string) *template.Template { f, err := internal.Templates.Open("templates/" + name + ".html") if err != nil { log.Panicf("%v: %v", name, err) // nolint: revive // Called during initialization. } defer func() { if err = f.Close(); err != nil { log.Panicf("%v: %v", name, err) // nolint: revive // Called during initialization. } }() text, err := io.ReadAll(f) if err != nil { log.Panicf("%v: %v", name, err) // nolint: revive // Called during initialization. } return template.Must(template.New(name).Funcs(templateFunctions).Parse(string(text))) } func spanRowFormatter(r spanRow) template.HTML { if !r.SpanContext.IsValid() { return "" } col := "black" if r.SpanContext.IsSampled() { col = "blue" } if r.ParentSpanContext.IsValid() { return template.HTML(fmt.Sprintf(`trace_id: %s span_id: %s parent_span_id: %s`, col, r.SpanContext.TraceID(), r.SpanContext.SpanID(), r.ParentSpanContext.SpanID())) } return template.HTML(fmt.Sprintf(`trace_id: %s span_id: %s`, col, r.SpanContext.TraceID(), r.SpanContext.SpanID())) } func even(x int) bool { return x%2 == 0 } open-telemetry-opentelemetry-go-contrib-2135499/zpages/tracez.go000066400000000000000000000165751443314701600247510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2017, OpenCensus Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages // import "go.opentelemetry.io/contrib/zpages" import ( "fmt" "log" "net/http" "sort" "strconv" "strings" "time" "go.opentelemetry.io/otel/attribute" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) const ( // spanNameQueryField is the header for span name. spanNameQueryField = "zspanname" // spanTypeQueryField is the header for type (running = 0, latency = 1, error = 2) to display. spanTypeQueryField = "ztype" // spanLatencyBucketQueryField is the header for latency based samples. // Default is [0, 8] representing the latency buckets, where 0 is the first one. spanLatencyBucketQueryField = "zlatencybucket" // maxTraceMessageLength is the maximum length of a message in tracez output. maxTraceMessageLength = 1024 ) type summaryTableData struct { Header []string LatencyBucketNames []string Links bool TracesEndpoint string Rows []summaryTableRowData } type summaryTableRowData struct { Name string Active int Latency []int Errors int } // traceTableData contains data for the trace data template. type traceTableData struct { Name string Num int Rows []spanRow } var _ http.Handler = (*tracezHandler)(nil) type tracezHandler struct { sp *SpanProcessor } // NewTracezHandler returns an http.Handler that can be used to serve HTTP requests for trace zpages. func NewTracezHandler(sp *SpanProcessor) http.Handler { return &tracezHandler{sp: sp} } // ServeHTTP implements the http.Handler and is capable of serving "tracez" HTTP requests. func (th *tracezHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := r.ParseForm(); err != nil { w.WriteHeader(http.StatusBadRequest) return } spanName := r.Form.Get(spanNameQueryField) spanType, _ := strconv.Atoi(r.Form.Get(spanTypeQueryField)) spanSubtype, _ := strconv.Atoi(r.Form.Get(spanLatencyBucketQueryField)) if err := headerTemplate.Execute(w, headerData{Title: "Trace Spans"}); err != nil { log.Printf("zpages: executing template: %v", err) } if err := summaryTableTemplate.Execute(w, th.getSummaryTableData()); err != nil { log.Printf("zpages: executing template: %v", err) } if spanName != "" { if err := tracesTableTemplate.Execute(w, th.getTraceTableData(spanName, spanType, spanSubtype)); err != nil { log.Printf("zpages: executing template: %v", err) } } if err := footerTemplate.Execute(w, nil); err != nil { log.Printf("zpages: executing template: %v", err) } } func (th *tracezHandler) getTraceTableData(spanName string, spanType, latencyBucket int) traceTableData { var spans []sdktrace.ReadOnlySpan switch spanType { case 0: // active spans = th.sp.activeSpans(spanName) case 1: // latency spans = th.sp.spansByLatency(spanName, latencyBucket) case 2: // error spans = th.sp.errorSpans(spanName) } data := traceTableData{ Name: spanName, Num: len(spans), } for _, s := range spans { data.Rows = append(data.Rows, spanRows(s)...) } return data } func (th *tracezHandler) getSummaryTableData() summaryTableData { data := summaryTableData{ Links: true, TracesEndpoint: "tracez", } data.Header = []string{"Name", "active"} // An implicit 0 lower bound latency bucket is always present. latencyBuckets := append([]time.Duration{0}, defaultBoundaries.durations...) for _, l := range latencyBuckets { s := fmt.Sprintf(">%v", l) data.Header = append(data.Header, s) data.LatencyBucketNames = append(data.LatencyBucketNames, s) } data.Header = append(data.Header, "Errors") for name, s := range th.sp.spansPerMethod() { row := summaryTableRowData{Name: name, Active: s.activeSpans, Errors: s.errorSpans, Latency: s.latencySpans} data.Rows = append(data.Rows, row) } sort.Slice(data.Rows, func(i, j int) bool { return data.Rows[i].Name < data.Rows[j].Name }) return data } type spanRow struct { Fields [3]string trace.SpanContext ParentSpanContext trace.SpanContext } type events []sdktrace.Event func (e events) Len() int { return len(e) } func (e events) Less(i, j int) bool { return e[i].Time.Before(e[j].Time) } func (e events) Swap(i, j int) { e[i], e[j] = e[j], e[i] } type attributes []attribute.KeyValue func (e attributes) Len() int { return len(e) } func (e attributes) Less(i, j int) bool { return string(e[i].Key) < string(e[j].Key) } func (e attributes) Swap(i, j int) { e[i], e[j] = e[j], e[i] } func spanRows(s sdktrace.ReadOnlySpan) []spanRow { start := s.StartTime() lasty, lastm, lastd := start.Date() wholeTime := func(t time.Time) string { return t.Format("2006/01/02-15:04:05") + fmt.Sprintf(".%06d", t.Nanosecond()/1000) } formatTime := func(t time.Time) string { y, m, d := t.Date() if y == lasty && m == lastm && d == lastd { return t.Format(" 15:04:05") + fmt.Sprintf(".%06d", t.Nanosecond()/1000) } lasty, lastm, lastd = y, m, d return wholeTime(t) } lastTime := start formatElapsed := func(t time.Time) string { d := t.Sub(lastTime) lastTime = t u := int64(d / 1000) // There are five cases for duration printing: // -1234567890s // -1234.123456 // .123456 // 12345.123456 // 12345678901s switch { case u < -9999999999: return fmt.Sprintf("%11ds", u/1e6) case u < 0: sec := u / 1e6 u -= sec * 1e6 return fmt.Sprintf("%5d.%06d", sec, -u) case u < 1e6: return fmt.Sprintf(" .%6d", u) case u <= 99999999999: sec := u / 1e6 u -= sec * 1e6 return fmt.Sprintf("%5d.%06d", sec, u) default: return fmt.Sprintf("%11ds", u/1e6) } } firstRow := spanRow{Fields: [3]string{wholeTime(start), "", ""}, SpanContext: s.SpanContext(), ParentSpanContext: s.Parent()} if s.EndTime().IsZero() { firstRow.Fields[1] = " " } else { firstRow.Fields[1] = formatElapsed(s.EndTime()) lastTime = start } out := []spanRow{firstRow} formatAttributes := func(a attributes) string { sort.Sort(a) var s []string for i := range a { s = append(s, fmt.Sprintf("%s=%v", a[i].Key, a[i].Value.Emit())) } return "Attributes:{" + strings.Join(s, ", ") + "}" } msg := fmt.Sprintf("Status{Code=%s, description=%q}", s.Status().Code.String(), s.Status().Description) out = append(out, spanRow{Fields: [3]string{"", "", msg}}) if len(s.Attributes()) != 0 { out = append(out, spanRow{Fields: [3]string{"", "", formatAttributes(s.Attributes())}}) } es := events(s.Events()) sort.Sort(es) for _, e := range es { msg := e.Name if len(e.Attributes) != 0 { msg = msg + " " + formatAttributes(e.Attributes) } row := spanRow{Fields: [3]string{ formatTime(e.Time), formatElapsed(e.Time), msg, }} out = append(out, row) } for i := range out { if len(out[i].Fields[2]) > maxTraceMessageLength { out[i].Fields[2] = out[i].Fields[2][:maxTraceMessageLength] } } return out } open-telemetry-opentelemetry-go-contrib-2135499/zpages/version.go000066400000000000000000000017671443314701600251430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zpages // import "go.opentelemetry.io/contrib/zpages" // Version is the current release version of the zpages span processor. func Version() string { return "0.42.0" // This string is updated by the pre_release.sh script during release } // SemVersion is the semantic version to be supplied to tracer/meter creation. // // Deprecated: Use [Version] instead. func SemVersion() string { return Version() }