diff --git a/.flake8 b/.flake8 index 8b2144c00f..5683cfc1f3 100644 --- a/.flake8 +++ b/.flake8 @@ -12,6 +12,10 @@ ignore = # allow whitespace before ':' (https://github.com/psf/black#slices) E203 + # conflicts with black + E701 + E704 + exclude = .bzr .git diff --git a/.github/component_owners.yml b/.github/component_owners.yml index ab14a41aec..efd15a6775 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -73,3 +73,6 @@ components: instrumentation/opentelemetry-instrumentation-psycopg: - federicobond + + processor/opentelemetry-processor-baggage: + - codeboten diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index f308c5757b..26789093f2 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -16,7 +16,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # history is needed to run git cherry-pick below fetch-depth: 0 @@ -40,4 +40,4 @@ jobs: gh pr create --title "[$GITHUB_REF_NAME] $title" \ --body "Clean cherry-pick of #$NUMBER to the \`$GITHUB_REF_NAME\` branch." \ --head $branch \ - --base $GITHUB_REF_NAME \ No newline at end of file + --base $GITHUB_REF_NAME diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 5238e01c4b..491ddd27fa 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -18,7 +18,7 @@ jobs: && github.actor != 'opentelemetrybot' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check for CHANGELOG changes run: | @@ -33,4 +33,4 @@ jobs: echo "No CHANGELOG was modified." echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." false - fi \ No newline at end of file + fi diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b979a3121b..8ef01d21cb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,16 +20,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: python - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 \ No newline at end of file + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/instrumentations_0.yml b/.github/workflows/instrumentations_0.yml index 5505fce008..a138621633 100644 --- a/.github/workflows/instrumentations_0.yml +++ b/.github/workflows/instrumentations_0.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: a1253585f66d63e7c05a19f070f3bfe0ab6460c1 + CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 jobs: instrumentations-0: @@ -104,16 +104,16 @@ jobs: package: "grpc" steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python ${{ env[matrix.python-version] }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ env[matrix.python-version] }} - name: Install tox run: pip install tox - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox diff --git a/.github/workflows/instrumentations_1.yml b/.github/workflows/instrumentations_1.yml index 978642a7a3..904f2ee999 100644 --- a/.github/workflows/instrumentations_1.yml +++ b/.github/workflows/instrumentations_1.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: a1253585f66d63e7c05a19f070f3bfe0ab6460c1 + CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 jobs: instrumentations-1: @@ -31,7 +31,7 @@ jobs: - "richconsole" - "psycopg" - "prometheus-remote-write" - - "sdkextension-aws" + - "sdk-extension-aws" - "propagator-aws-xray" - "propagator-ot-trace" - "resource-detector-container" @@ -43,16 +43,16 @@ jobs: package: "prometheus-remote-write" steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python ${{ env[matrix.python-version] }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ env[matrix.python-version] }} - name: Install tox run: pip install tox - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..39afb3ee96 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,121 @@ +name: Lint tests + +on: + push: + branches-ignore: + - 'release/*' + pull_request: +env: + CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 + +jobs: + lint-3_11: + strategy: + fail-fast: false # ensures the entire test matrix is run, even if one permutation fails + matrix: + package: + - "distro" + - "exporter-prometheus-remote-write" + - "exporter-richconsole" + - "instrumentation-aio-pika" + - "instrumentation-aiohttp-client" + - "instrumentation-aiohttp-server" + - "instrumentation-aiopg" + - "instrumentation-asgi" + - "instrumentation-asyncio" + - "instrumentation-asyncpg" + - "instrumentation-aws-lambda" + - "instrumentation-boto" + - "instrumentation-boto3sqs" + - "instrumentation-botocore" + - "instrumentation-cassandra" + - "instrumentation-celery" + - "instrumentation-confluent-kafka" + - "instrumentation-dbapi" + - "instrumentation-django" + - "instrumentation-elasticsearch" + - "instrumentation-falcon" + - "instrumentation-fastapi" + - "instrumentation-flask" + - "instrumentation-grpc" + - "instrumentation-httpx" + - "instrumentation-jinja2" + - "instrumentation-kafka-python" + - "instrumentation-logging" + - "instrumentation-mysql" + - "instrumentation-mysqlclient" + - "instrumentation-psycopg" + - "instrumentation-psycopg2" + - "instrumentation-pymemcache" + - "instrumentation-pymongo" + - "instrumentation-pymysql" + - "instrumentation-pyramid" + - "instrumentation-redis" + - "instrumentation-remoulade" + - "instrumentation-requests" + - "instrumentation-sio-pika" + - "instrumentation-sqlalchemy" + - "instrumentation-sqlite3" + - "instrumentation-starlette" + - "instrumentation-system-metrics" + - "instrumentation-threading" + - "instrumentation-tornado" + - "instrumentation-tortoiseorm" + - "instrumentation-urllib" + - "instrumentation-urllib3" + - "instrumentation-wsgi" + - "opentelemetry-instrumentation" + - "processor-baggage" + - "propagator-aws-xray" + - "propagator-ot-trace" + - "resource-detector-container" + - "sdk-extension-aws" + os: [ubuntu-20.04] + runs-on: ubuntu-20.04 + steps: + - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install tox + run: pip install tox + - name: Cache tox environment + # Preserves .tox directory between runs for faster installs + uses: actions/cache@v4 + with: + path: | + .tox + ~/.cache/pip + key: v7-build-tox-cache-${{ matrix.package }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} + - name: run tox + run: tox -e lint-${{ matrix.package }} + + lint-3_8: + strategy: + fail-fast: false # ensures the entire test matrix is run, even if one permutation fails + matrix: + package: + - "instrumentation-sklearn" + os: [ubuntu-20.04] + runs-on: ubuntu-20.04 + steps: + - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + - name: Set up Python 3.8 + uses: actions/setup-python@v5 + with: + python-version: 3.8 + - name: Install tox + run: pip install tox + - name: Cache tox environment + # Preserves .tox directory between runs for faster installs + uses: actions/cache@v4 + with: + path: | + .tox + ~/.cache/pip + key: v7-build-tox-cache-${{ matrix.package }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} + - name: run tox + run: tox -e lint-${{ matrix.package }} diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 49b9c89560..7c854d436d 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -6,7 +6,7 @@ jobs: prepare-patch-release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | if [[ ! $GITHUB_REF_NAME =~ ^release/v[0-9]+\.[0-9]+\.x-0\.[0-9]+bx$ ]]; then @@ -50,7 +50,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_VERSION $UNSTABLE_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -79,4 +79,4 @@ jobs: gh pr create --title "[$GITHUB_REF_NAME] $message" \ --body "$message." \ --head $branch \ - --base $GITHUB_REF_NAME \ No newline at end of file + --base $GITHUB_REF_NAME diff --git a/.github/workflows/prepare-release-branch.yml b/.github/workflows/prepare-release-branch.yml index a4caf86ebe..6818772acf 100644 --- a/.github/workflows/prepare-release-branch.yml +++ b/.github/workflows/prepare-release-branch.yml @@ -10,7 +10,7 @@ jobs: prereqs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Verify prerequisites env: @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest needs: prereqs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Create release branch env: @@ -77,7 +77,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_VERSION $UNSTABLE_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -112,7 +112,7 @@ jobs: runs-on: ubuntu-latest needs: prereqs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set environment variables env: @@ -161,7 +161,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_NEXT_VERSION $UNSTABLE_NEXT_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -192,4 +192,4 @@ jobs: gh pr create --title "$message" \ --body "$body" \ --head $branch \ - --base main \ No newline at end of file + --base main diff --git a/.github/workflows/publish-a-package-from-tag.yml b/.github/workflows/publish-a-package-from-tag.yml index 2c07bf5d7a..a64f5fcf15 100644 --- a/.github/workflows/publish-a-package-from-tag.yml +++ b/.github/workflows/publish-a-package-from-tag.yml @@ -10,8 +10,8 @@ jobs: name: Publish package from tag runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.9' - name: Log tag that triggered publish workflow diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6c267003a..b60ebc7599 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set environment variables run: | @@ -56,15 +56,15 @@ jobs: # check out main branch to verify there won't be problems with merging the change log # at the end of this workflow - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: main # back to the release branch - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # next few steps publish to pypi - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v5 with: python-version: '3.8' @@ -127,7 +127,7 @@ jobs: --discussion-category announcements \ v$UNSTABLE_VERSION - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # the step below is creating a pull request against main ref: main diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 0000000000..68d12b805f --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,19 @@ +name: Shellcheck + +on: + push: + branches-ignore: + - 'release/*' + pull_request: + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install shellcheck + run: sudo apt update && sudo apt install --assume-yes shellcheck + + - name: Run shellcheck + run: find . -name \*.sh | xargs shellcheck --severity=warning diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3bc748551b..a129c6e7ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,31 +6,28 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: a1253585f66d63e7c05a19f070f3bfe0ab6460c1 + CORE_REPO_SHA: 47d5ad7aae5aef31238ca66e55dc550b307c7b35 jobs: misc: strategy: fail-fast: false matrix: - tox-environment: [ "docker-tests", "spellcheck", "lint", "docs", "generate" ] + tox-environment: [ "docker-tests", "spellcheck", "docs", "generate" ] name: ${{ matrix.tox-environment }} runs-on: ubuntu-20.04 steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install tox run: pip install tox - - name: Install libsnappy-dev - if: ${{ matrix.tox-environment == 'lint' }} - run: sudo apt-get install -y libsnappy-dev - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox diff --git a/.pylintrc b/.pylintrc index 5ea4385ea0..114dadef75 100644 --- a/.pylintrc +++ b/.pylintrc @@ -81,6 +81,7 @@ disable=missing-docstring, missing-module-docstring, # temp-pylint-upgrade import-error, # needed as a workaround as reported here: https://github.com/open-telemetry/opentelemetry-python-contrib/issues/290 cyclic-import, + not-context-manager # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/.readthedocs.yml b/.readthedocs.yml index 3dcf0e5cf6..2a3c920b45 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,9 +6,10 @@ sphinx: configuration: docs/conf.py build: - image: latest + os: "ubuntu-22.04" + tools: + python: "3.8" python: - version: 3.8 install: - requirements: docs-requirements.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d2892a135..498eb44a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Breaking changes + +- Rename `type` attribute to `asgi.event.type` in `opentelemetry-instrumentation-asgi` + ([#2300](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2300)) +- Rename AwsLambdaInstrumentor span attributes `faas.id` to `cloud.resource_id`, `faas.execution` to `faas.invocation_id` + ([#2372](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2372)) +- Drop support for instrumenting elasticsearch client < 6` + ([#2422](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2422)) +- `opentelemetry-instrumentation-wsgi` Add `http.method` to `span.name` + ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) +- `opentelemetry-instrumentation-flask` Add `http.method` to `span.name` + ([#2454](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2454)) + +### Added + +- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the + `opentelemetry_resource_detector` entry point + ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) +- `opentelemetry-instrumentation-wsgi` Implement new semantic convention opt-in with stable http semantic conventions + ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) +- `opentelemetry-instrumentation-flask` Implement new semantic convention opt-in with stable http semantic conventions + ([#2454](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2454)) +- `opentelemetry-instrumentation-threading` Initial release for threading + ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) +- `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported + only for global, non channel specific instrumentation) + ([#2397](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2397))) +- `opentelemetry-processor-baggage` Initial release + ([#2436](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2436)) + +### Fixed + +- `opentelemetry-instrumentation-grpc` AioClientInterceptor should propagate with a Metadata object + ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) +- `opentelemetry-instrumentation-boto3sqs` Instrument Session and resource + ([#2161](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2161)) +- `opentelemetry-instrumentation-aws-lambda` Fix exception handling for events with requestContext + ([#2418](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2418)) +- Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version + ([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404)) + +## Version 1.24.0/0.45b0 (2024-03-28) + +### Added + +- `opentelemetry-instrumentation-psycopg` Async Instrumentation for psycopg 3.x + ([#2146](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2146)) + +### Fixed - `opentelemetry-instrumentation-celery` Allow Celery instrumentation to be installed multiple times ([#2342](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2342)) - Align gRPC span status codes to OTEL specification @@ -15,12 +64,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2297](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/2297)) - Ensure all http.server.duration metrics have the same description ([#2151](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/2298)) +- Fix regression in httpx `request.url` not being of type `httpx.URL` after `0.44b0` + ([#2359](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2359)) - Avoid losing repeated HTTP headers ([#2266](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2266)) +- `opentelemetry-instrumentation-elasticsearch` Don't send bulk request body as db statement + ([#2355](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2355)) +- AwsLambdaInstrumentor sets `cloud.account.id` span attribute + ([#2367](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2367)) ## Version 1.23.0/0.44b0 (2024-02-23) -- Drop uspport for 3.7 +- Drop support for 3.7 ([#2151](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2151)) - `opentelemetry-resource-detector-azure` Added 10s timeout to VM Resource Detector ([#2119](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2119)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c18392bc7..3c4bae0f47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,13 +62,13 @@ You can run `tox` with the following arguments: - `tox -e py311-test-instrumentation-aiopg` to e.g. run the aiopg instrumentation unit tests under a specific Python version - `tox -e spellcheck` to run a spellcheck on all the code -- `tox -e lint` to run lint checks on all code +- `tox -e lint-some-package` to run lint checks on `some-package` `black` and `isort` are executed when `tox -e lint` is run. The reported errors can be tedious to fix manually. An easier way to do so is: -1. Run `.tox/lint/bin/black .` -2. Run `.tox/lint/bin/isort .` +1. Run `.tox/lint-some-package/bin/black .` +2. Run `.tox/lint-some-package/bin/isort .` See [`tox.ini`](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/tox.ini) diff --git a/LICENSE b/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/LICENSE.Apache b/LICENSE.Apache index bff56b5431..261eeb9e9f 100644 --- a/LICENSE.Apache +++ b/LICENSE.Apache @@ -178,7 +178,7 @@ 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 "{}" + 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 @@ -186,7 +186,8 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016 Datadog, Inc. + 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 diff --git a/README.md b/README.md index c315b4a876..133acf81f6 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,15 @@ To release a package as `1.0` stable, the package: - e.g. If an instrumentation package uses flags, a token as context, or parameters that are not typical of the `BaseInstrumentor` class, these are documented - After the release of `1.0`, a CODEOWNER may no longer feel like they have the bandwidth to meet the responsibilities of maintaining the package. That's not a problem at all, life happens! However, if that is the case, we ask that the CODEOWNER please raise an issue indicating that they would like to be removed as a CODEOWNER so that they don't get pinged on future PRs. Ultimately, we hope to use that issue to find a new CODEOWNER. +## Semantic Convention status of instrumentations + +In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the [semantic convention migration plan](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/migration-guide.md) for several instrumentations. Currently this plan is only being adopted for HTTP-related instrumentations, but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `experimental`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan. + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) -We meet weekly on Thursday, and the time of the meeting alternates between 9AM PT and 4PM PT. The meeting is subject to change depending on contributors' availability. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com) for specific dates and for the Zoom link. +We meet weekly on Thursday at 9AM PT. The meeting is subject to change depending on contributors' availability. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=c_2bf73e3b6b530da4babd444e72b76a6ad893a5c3f43cf40467abc7a9a897f977%40group.calendar.google.com) for specific dates and for the Zoom link. Meeting notes are available as a public [Google doc](https://docs.google.com/document/d/1CIMGoIOZ-c3-igzbd6_Pnxx1SjAkjwqoYSUWxPY8XIs/edit). For edit access, get in touch on [GitHub Discussions](https://github.com/open-telemetry/opentelemetry-python/discussions). @@ -108,14 +112,20 @@ Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telem - [Aaron Abbott](https://github.com/aabmass), Google - [Jeremy Voss](https://github.com/jeremydvoss), Microsoft +- [Owais Lone](https://github.com/owais), Splunk +- [Pablo Collins](https://github.com/pmcollins), Splunk +- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic - [Sanket Mehta](https://github.com/sanketmehta28), Cisco +- [Srikanth Chekuri](https://github.com/srikanthccv), signoz.io +- [Tammy Baylis](https://github.com/tammy-baylis-swi), SolarWinds Emeritus Approvers: +- [Ashutosh Goel](https://github.com/ashu658), Cisco - [Héctor Hernández](https://github.com/hectorhdzg), Microsoft -- [Yusuke Tsutsumi](https://github.com/toumorokoshi), Google +- [Nikolay Sokolik](https://github.com/oxeye-nikolay), Oxeye +- [Nikolay Sokolik](https://github.com/nikosokolik), Oxeye - [Nathaniel Ruiz Nowell](https://github.com/NathanielRN), AWS -- [Ashutosh Goel](https://github.com/ashu658), Cisco *Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).* @@ -129,7 +139,7 @@ Emeritus Maintainers: - [Alex Boten](https://github.com/codeboten), Lightstep - [Owais Lone](https://github.com/owais), Splunk -- [Srikanth Chekuri](https://github.com/srikanthccv), signoz.io +- [Yusuke Tsutsumi](https://github.com/toumorokoshi), Google *Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).* diff --git a/_template/pyproject.toml b/_template/pyproject.toml index 55607cc9b1..ca3da89a30 100644 --- a/_template/pyproject.toml +++ b/_template/pyproject.toml @@ -31,12 +31,6 @@ dependencies = [ "opentelemetry-api ~= 1.12", ] -[project.optional-dependencies] -test = [ - # add any test dependencies here - "", -] - [project.entry-points.opentelemetry_instrumentor] # REPLACE ME: the entrypoint for the instrumentor e.g # sqlalchemy = "opentelemetry.instrumentation.sqlalchemy:SQLAlchemyInstrumentor" diff --git a/_template/version.py b/_template/version.py index 2b23bc4994..ff4933b20b 100644 --- a/_template/version.py +++ b/_template/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/dev-requirements.txt b/dev-requirements.txt index fffb4c445d..1c49c57b7e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,7 +1,7 @@ pylint==3.0.2 flake8==6.1.0 isort==5.12.0 -black==22.3.0 +black==24.3.0 httpretty==1.1.4 mypy==0.931 sphinx==7.1.2 diff --git a/docs-requirements.txt b/docs-requirements.txt index aff449fcf8..72f4472902 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -28,7 +28,7 @@ boto3~=1.0 cassandra-driver~=3.25 celery>=4.0 confluent-kafka>= 1.8.2,<= 2.3.0 -elasticsearch>=2.0,<9.0 +elasticsearch>=6.0,<9.0 flask~=2.0 falcon~=2.0 grpcio~=1.27 diff --git a/docs/index.rst b/docs/index.rst index 5203c377e4..e2bf32e12e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,7 +22,7 @@ installed separately via pip: pip install opentelemetry-exporter-{exporter} pip install opentelemetry-instrumentation-{instrumentation} - pip install opentelemetry-sdk-extension-{sdkextension} + pip install opentelemetry-sdk-extension-{sdk-extension} A complete list of packages can be found at the `Contrib repo instrumentation `_ diff --git a/docs/instrumentation/threading/threading.rst b/docs/instrumentation/threading/threading.rst new file mode 100644 index 0000000000..06bca89a49 --- /dev/null +++ b/docs/instrumentation/threading/threading.rst @@ -0,0 +1,7 @@ +OpenTelemetry Threading Instrumentation +======================================= + +.. automodule:: opentelemetry.instrumentation.threading + :members: + :undoc-members: + :show-inheritance: diff --git a/eachdist.ini b/eachdist.ini index 8d6bdbb6be..60f1154a83 100644 --- a/eachdist.ini +++ b/eachdist.ini @@ -16,7 +16,7 @@ sortfirst= ext/* [stable] -version=1.24.0.dev +version=1.25.0.dev packages= opentelemetry-sdk @@ -34,7 +34,7 @@ packages= opentelemetry-api [prerelease] -version=0.45b0.dev +version=0.46b0.dev packages= all diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh b/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh index 5f6129df55..a07181add3 100755 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh @@ -6,7 +6,6 @@ PROTO_VERSION=v1.3.2 # SRC_DIR is from protoc perspective. ie its the destination for our checkouts/clones SRC_DIR=opentelemetry/exporter/prometheus_remote_write/gen/ -DST_DIR=../src/opentelemetry/exporter/prometheus_remote_write/gen/ #TODO: # Check that black & protoc are installed properly diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/pyproject.toml b/exporter/opentelemetry-exporter-prometheus-remote-write/pyproject.toml index a6dea9a9de..b0006a0682 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/pyproject.toml +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/pyproject.toml @@ -31,9 +31,6 @@ dependencies = [ "python-snappy ~= 0.6", ] -[project.optional-dependencies] -test = [] - [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/exporter/opentelemetry-exporter-prometheus-remote-write" diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py index 3efcb36536..f8724074f6 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py @@ -34,13 +34,13 @@ DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b"Z\006prompb" _WRITEREQUEST.fields_by_name["timeseries"]._options = None - _WRITEREQUEST.fields_by_name[ - "timeseries" - ]._serialized_options = b"\310\336\037\000" + _WRITEREQUEST.fields_by_name["timeseries"]._serialized_options = ( + b"\310\336\037\000" + ) _WRITEREQUEST.fields_by_name["metadata"]._options = None - _WRITEREQUEST.fields_by_name[ - "metadata" - ]._serialized_options = b"\310\336\037\000" + _WRITEREQUEST.fields_by_name["metadata"]._serialized_options = ( + b"\310\336\037\000" + ) _WRITEREQUEST._serialized_start = 216 _WRITEREQUEST._serialized_end = 338 _READREQUEST._serialized_start = 341 diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py index fbfa2123ad..30cf2e38cc 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py @@ -31,31 +31,31 @@ DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b"Z\006prompb" _EXEMPLAR.fields_by_name["labels"]._options = None - _EXEMPLAR.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _EXEMPLAR.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["labels"]._options = None - _TIMESERIES.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["samples"]._options = None - _TIMESERIES.fields_by_name[ - "samples" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["samples"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["exemplars"]._options = None - _TIMESERIES.fields_by_name[ - "exemplars" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["exemplars"]._serialized_options = ( + b"\310\336\037\000" + ) _LABELS.fields_by_name["labels"]._options = None _LABELS.fields_by_name["labels"]._serialized_options = b"\310\336\037\000" _CHUNKEDSERIES.fields_by_name["labels"]._options = None - _CHUNKEDSERIES.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _CHUNKEDSERIES.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _CHUNKEDSERIES.fields_by_name["chunks"]._options = None - _CHUNKEDSERIES.fields_by_name[ - "chunks" - ]._serialized_options = b"\310\336\037\000" + _CHUNKEDSERIES.fields_by_name["chunks"]._serialized_options = ( + b"\310\336\037\000" + ) _METRICMETADATA._serialized_start = 152 _METRICMETADATA._serialized_end = 400 _METRICMETADATA_METRICTYPE._serialized_start = 279 diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/version.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/version.py index 2b23bc4994..ff4933b20b 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/version.py +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt b/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt new file mode 100644 index 0000000000..40c4886fd7 --- /dev/null +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt @@ -0,0 +1,24 @@ +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +cramjam==2.8.1 +Deprecated==1.2.14 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +protobuf==4.25.3 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-snappy==0.7.1 +requests==2.31.0 +tomli==2.0.1 +typing_extensions==4.10.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e exporter/opentelemetry-exporter-prometheus-remote-write diff --git a/exporter/opentelemetry-exporter-richconsole/pyproject.toml b/exporter/opentelemetry-exporter-richconsole/pyproject.toml index c8a509f643..9fb32c772c 100644 --- a/exporter/opentelemetry-exporter-richconsole/pyproject.toml +++ b/exporter/opentelemetry-exporter-richconsole/pyproject.toml @@ -26,13 +26,10 @@ classifiers = [ dependencies = [ "opentelemetry-api ~= 1.12", "opentelemetry-sdk ~= 1.12", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "rich>=10.0.0", ] -[project.optional-dependencies] -test = [] - [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/exporter/opentelemetry-exporter-richconsole" diff --git a/exporter/opentelemetry-exporter-richconsole/src/opentelemetry/exporter/richconsole/version.py b/exporter/opentelemetry-exporter-richconsole/src/opentelemetry/exporter/richconsole/version.py index 2b23bc4994..ff4933b20b 100644 --- a/exporter/opentelemetry-exporter-richconsole/src/opentelemetry/exporter/richconsole/version.py +++ b/exporter/opentelemetry-exporter-richconsole/src/opentelemetry/exporter/richconsole/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/exporter/opentelemetry-exporter-richconsole/test-requirements.txt b/exporter/opentelemetry-exporter-richconsole/test-requirements.txt new file mode 100644 index 0000000000..42d2ec7b4c --- /dev/null +++ b/exporter/opentelemetry-exporter-richconsole/test-requirements.txt @@ -0,0 +1,21 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +flaky==3.7.0 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +markdown-it-py==3.0.0 +mdurl==0.1.2 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +Pygments==2.17.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +rich==13.7.1 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e exporter/opentelemetry-exporter-richconsole diff --git a/gen-requirements.txt b/gen-requirements.txt index 0f96f12a56..de84b72c1e 100644 --- a/gen-requirements.txt +++ b/gen-requirements.txt @@ -1,6 +1,6 @@ -c dev-requirements.txt astor==0.8.1 -jinja2~=2.7 +jinja2==3.1.3 markupsafe==2.0.1 isort black diff --git a/instrumentation/README.md b/instrumentation/README.md index 0cce7e5de7..c73d0f7c0a 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -1,50 +1,51 @@ -| Instrumentation | Supported Packages | Metrics support | -| --------------- | ------------------ | --------------- | -| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No -| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No -| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No -| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No -| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No -| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No -| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No -| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No -| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No -| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No -| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No -| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No -| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No -| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.3.0 | No -| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No -| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes -| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No -| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | Yes -| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes -| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes -| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No -| [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No -| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No -| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0 | No -| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No -| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python ~= 8.0 | No -| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No -| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No -| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No -| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No -| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No -| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No -| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No -| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes -| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No -| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No -| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes -| [opentelemetry-instrumentation-sklearn](./opentelemetry-instrumentation-sklearn) | scikit-learn ~= 0.24.0 | No -| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy | Yes -| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No -| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette ~= 0.13.0 | Yes -| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No -| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes -| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No -| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes -| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes -| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes \ No newline at end of file +| Instrumentation | Supported Packages | Metrics support | Semconv status | +| --------------- | ------------------ | --------------- | -------------- | +| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No | experimental +| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No | experimental +| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No | experimental +| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No | experimental +| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No | experimental +| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No | experimental +| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No | experimental +| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No | experimental +| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No | experimental +| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No | experimental +| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.3.0 | No | experimental +| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | experimental +| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | experimental +| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No | experimental +| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | Yes | experimental +| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | experimental +| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | migration +| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No | experimental +| [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No | experimental +| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No | experimental +| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0 | No | experimental +| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No | experimental +| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python ~= 8.0 | No | experimental +| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No | experimental +| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No | experimental +| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No | experimental +| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No | experimental +| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No | experimental +| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No | experimental +| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No | experimental +| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes | experimental +| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No | experimental +| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No | experimental +| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes | migration +| [opentelemetry-instrumentation-sklearn](./opentelemetry-instrumentation-sklearn) | scikit-learn ~= 0.24.0 | No | experimental +| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy | Yes | experimental +| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No | experimental +| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette ~= 0.13.0 | Yes | experimental +| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | experimental +| [opentelemetry-instrumentation-threading](./opentelemetry-instrumentation-threading) | threading | No | experimental +| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes | experimental +| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No | experimental +| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes | experimental +| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes | experimental +| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes | migration \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml index e79dac2866..73c10fffce 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.5", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py index b73afa62b3..c62b1ea9bf 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py @@ -47,8 +47,13 @@ def set_destination(self, destination: str): self._attributes[SpanAttributes.MESSAGING_DESTINATION] = destination def set_channel(self, channel: AbstractChannel): - connection = channel.connection - if getattr(connection, "connection", None): + if hasattr(channel, "_connection"): + # aio_rmq 9.1 and above removed the connection attribute from the abstract listings + connection = channel._connection + else: + # aio_rmq 9.0.5 and below + connection = channel.connection + if hasattr(connection, "connection"): # aio_rmq 7 url = connection.connection.url else: @@ -57,7 +62,7 @@ def set_channel(self, channel: AbstractChannel): self._attributes.update( { SpanAttributes.NET_PEER_NAME: url.host, - SpanAttributes.NET_PEER_PORT: url.port, + SpanAttributes.NET_PEER_PORT: url.port or 5672, } ) diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/version.py b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/version.py +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt index 3250c93947..7e1aa15fa0 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt @@ -1,5 +1,5 @@ -aio-pika==9.4.0 -aiormq==6.8.0 +aio-pika==9.0.5 +aiormq==6.7.1 asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 @@ -8,7 +8,7 @@ importlib-metadata==6.11.0 iniconfig==2.0.0 multidict==6.0.5 packaging==23.2 -pamqp==3.3.0 +pamqp==3.2.1 pluggy==1.4.0 py==1.11.0 py-cpuinfo==9.0.0 diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt new file mode 100644 index 0000000000..65c2ff8f0c --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt @@ -0,0 +1,23 @@ +aio-pika==9.4.1 +aiormq==6.8.0 +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +multidict==6.0.5 +packaging==23.2 +pamqp==3.3.0 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-aio-pika diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE b/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml index b7c0e52b7c..17b92b2cf8 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/version.py index f7a124c7b8..604195c10e 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 3ea2340d89..f85cfd6e39 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE b/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml index b6c54b658b..4a01639d37 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/version.py b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-asgi/LICENSE b/instrumentation/opentelemetry-instrumentation-asgi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asgi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml index 81c83b07e9..a4072bac7d 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml @@ -26,9 +26,9 @@ classifiers = [ dependencies = [ "asgiref ~= 3.0", "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py index 4084b4ba2a..90717f77fe 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -347,11 +347,11 @@ def collect_custom_headers_attributes( Refer specifications: - https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers """ - # Decode headers before processing. headers: DefaultDict[str, list[str]] = defaultdict(list) raw_headers = scope_or_response_message.get("headers") if raw_headers: for key, value in raw_headers: + # Decode headers before processing. headers[key.decode()].append(value.decode()) return sanitize.sanitize_header_values( @@ -668,7 +668,9 @@ async def otel_receive(): if receive_span.is_recording(): if message["type"] == "websocket.receive": set_status_code(receive_span, 200) - receive_span.set_attribute("type", message["type"]) + receive_span.set_attribute( + "asgi.event.type", message["type"] + ) return message return otel_receive @@ -689,9 +691,9 @@ async def otel_send(message: dict[str, Any]): if send_span.is_recording(): if message["type"] == "http.response.start": status_code = message["status"] - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = status_code + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + status_code + ) set_status_code(server_span, status_code) set_status_code(send_span, status_code) @@ -699,7 +701,7 @@ async def otel_send(message: dict[str, Any]): elif message["type"] == "websocket.send": set_status_code(server_span, 200) set_status_code(send_span, 200) - send_span.set_attribute("type", message["type"]) + send_span.set_attribute("asgi.event.type", message["type"]) if ( server_span.is_recording() and server_span.kind == trace.SpanKind.SERVER diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/version.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/version.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py index 0b2a844d96..2a8fd1c1f0 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py @@ -268,20 +268,20 @@ def validate_outputs(self, outputs, error=None, modifiers=None): { "name": "GET / http receive", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "http.request"}, + "attributes": {"asgi.event.type": "http.request"}, }, { "name": "GET / http send", "kind": trace_api.SpanKind.INTERNAL, "attributes": { SpanAttributes.HTTP_STATUS_CODE: 200, - "type": "http.response.start", + "asgi.event.type": "http.response.start", }, }, { "name": "GET / http send", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "http.response.body"}, + "attributes": {"asgi.event.type": "http.response.body"}, }, { "name": "GET /", @@ -358,7 +358,7 @@ def add_more_body_spans(expected: list): more_body_span = { "name": "GET / http send", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "http.response.body"}, + "attributes": {"asgi.event.type": "http.response.body"}, } extra_spans = [more_body_span] * 3 expected[2:2] = extra_spans @@ -396,12 +396,12 @@ def add_body_and_trailer_span(expected: list): body_span = { "name": "GET / http send", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "http.response.body"}, + "attributes": {"asgi.event.type": "http.response.body"}, } trailer_span = { "name": "GET / http send", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "http.response.trailers"}, + "attributes": {"asgi.event.type": "http.response.trailers"}, } expected[2:2] = [body_span] expected[4:4] = [trailer_span] * 2 @@ -582,18 +582,18 @@ def test_websocket(self): { "name": "/ websocket receive", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "websocket.connect"}, + "attributes": {"asgi.event.type": "websocket.connect"}, }, { "name": "/ websocket send", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "websocket.accept"}, + "attributes": {"asgi.event.type": "websocket.accept"}, }, { "name": "/ websocket receive", "kind": trace_api.SpanKind.INTERNAL, "attributes": { - "type": "websocket.receive", + "asgi.event.type": "websocket.receive", SpanAttributes.HTTP_STATUS_CODE: 200, }, }, @@ -601,14 +601,14 @@ def test_websocket(self): "name": "/ websocket send", "kind": trace_api.SpanKind.INTERNAL, "attributes": { - "type": "websocket.send", + "asgi.event.type": "websocket.send", SpanAttributes.HTTP_STATUS_CODE: 200, }, }, { "name": "/ websocket receive", "kind": trace_api.SpanKind.INTERNAL, - "attributes": {"type": "websocket.disconnect"}, + "attributes": {"asgi.event.type": "websocket.disconnect"}, }, { "name": "/", diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 5354ea3cb4..540da184be 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.14", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-test-utils == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-test-utils == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncpg/pyproject.toml index bd9e26bbe4..6cdd2e7294 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/pyproject.toml @@ -25,18 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "asyncpg >= 0.12.0", ] -test = [ - "opentelemetry-instrumentation-asyncpg[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] asyncpg = "opentelemetry.instrumentation.asyncpg:AsyncPGInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py index 11c579f96a..798a5dc00b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py @@ -77,14 +77,14 @@ def _hydrate_span_from_args(connection, query, parameters) -> dict: if isinstance(addr, tuple): span_attributes[SpanAttributes.NET_PEER_NAME] = addr[0] span_attributes[SpanAttributes.NET_PEER_PORT] = addr[1] - span_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + span_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) elif isinstance(addr, str): span_attributes[SpanAttributes.NET_PEER_NAME] = addr - span_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + span_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) if query is not None: span_attributes[SpanAttributes.DB_STATEMENT] = query diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt new file mode 100644 index 0000000000..02d8fb2041 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +async-timeout==4.0.3 +asyncpg==0.29.0 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-asyncpg diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE b/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml index 6ab6e23ffc..3088c47dbe 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/pyproject.toml @@ -21,16 +21,13 @@ classifiers = [ "Programming Language :: Python :: 3.8", ] dependencies = [ - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-propagator-aws-xray == 1.0.1", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [] -test = [ - "opentelemetry-test-utils == 0.45b0.dev", -] [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aws-lambda" diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py index 130622f8c8..7614ba9813 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -340,21 +340,32 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches if span.is_recording(): lambda_context = args[1] # NOTE: The specs mention an exception here, allowing the - # `ResourceAttributes.FAAS_ID` attribute to be set as a span + # `SpanAttributes.CLOUD_RESOURCE_ID` attribute to be set as a span # attribute instead of a resource attribute. # # See more: - # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/faas.md#example + # https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#resource-detector span.set_attribute( - ResourceAttributes.FAAS_ID, + SpanAttributes.CLOUD_RESOURCE_ID, lambda_context.invoked_function_arn, ) span.set_attribute( - SpanAttributes.FAAS_EXECUTION, + SpanAttributes.FAAS_INVOCATION_ID, lambda_context.aws_request_id, ) + # NOTE: `cloud.account.id` can be parsed from the ARN as the fifth item when splitting on `:` + # + # See more: + # https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#all-triggers + account_id = lambda_context.invoked_function_arn.split(":")[4] + span.set_attribute( + ResourceAttributes.CLOUD_ACCOUNT_ID, + account_id, + ) + exception = None + result = None try: result = call_wrapped(*args, **kwargs) except Exception as exc: # pylint: disable=W0703 diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/version.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/version.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt new file mode 100644 index 0000000000..53e5b9ce6f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e propagator/opentelemetry-propagator-aws-xray +-e instrumentation/opentelemetry-instrumentation-aws-lambda diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py index 2fa4aafee5..f10953c754 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py @@ -17,13 +17,6 @@ from typing import Any, Callable, Dict from unittest import mock -from tests.mocks.api_gateway_http_api_event import ( - MOCK_LAMBDA_API_GATEWAY_HTTP_API_EVENT, -) -from tests.mocks.api_gateway_proxy_event import ( - MOCK_LAMBDA_API_GATEWAY_PROXY_EVENT, -) - from opentelemetry.environment_variables import OTEL_PROPAGATORS from opentelemetry.instrumentation.aws_lambda import ( _HANDLER, @@ -45,6 +38,11 @@ TraceContextTextMapPropagator, ) +from .mocks.api_gateway_http_api_event import ( + MOCK_LAMBDA_API_GATEWAY_HTTP_API_EVENT, +) +from .mocks.api_gateway_proxy_event import MOCK_LAMBDA_API_GATEWAY_PROXY_EVENT + class MockLambdaContext: def __init__(self, aws_request_id, invoked_function_arn): @@ -54,7 +52,7 @@ def __init__(self, aws_request_id, invoked_function_arn): MOCK_LAMBDA_CONTEXT = MockLambdaContext( aws_request_id="mock_aws_request_id", - invoked_function_arn="arn://mock-lambda-function-arn", + invoked_function_arn="arn:aws:lambda:us-east-1:123456:function:myfunction:myalias", ) MOCK_XRAY_TRACE_ID = 0x5FB7331105E8BB83207FA31D4D9CDB4C @@ -145,8 +143,13 @@ def test_active_tracing(self): self.assertSpanHasAttributes( span, { - ResourceAttributes.FAAS_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn, - SpanAttributes.FAAS_EXECUTION: MOCK_LAMBDA_CONTEXT.aws_request_id, + SpanAttributes.CLOUD_RESOURCE_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn, + SpanAttributes.FAAS_INVOCATION_ID: MOCK_LAMBDA_CONTEXT.aws_request_id, + ResourceAttributes.CLOUD_ACCOUNT_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn.split( + ":" + )[ + 4 + ], }, ) @@ -431,6 +434,31 @@ def test_lambda_handles_handler_exception(self): exc_env_patch.stop() + def test_lambda_handles_handler_exception_with_api_gateway_proxy_event( + self, + ): + exc_env_patch = mock.patch.dict( + "os.environ", + {_HANDLER: "tests.mocks.lambda_function.handler_exc"}, + ) + exc_env_patch.start() + AwsLambdaInstrumentor().instrument() + # instrumentor re-raises the exception + with self.assertRaises(Exception): + mock_execute_lambda( + {"requestContext": {"http": {"method": "GET"}}} + ) + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + span = spans[0] + self.assertEqual(span.status.status_code, StatusCode.ERROR) + self.assertEqual(len(span.events), 1) + event = span.events[0] + self.assertEqual(event.name, "exception") + + exc_env_patch.stop() + def test_uninstrument(self): AwsLambdaInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-boto/LICENSE b/instrumentation/opentelemetry-instrumentation-boto/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-boto/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-boto/pyproject.toml b/instrumentation/opentelemetry-instrumentation-boto/pyproject.toml index 307a96e5aa..87a323f996 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-boto/pyproject.toml @@ -25,20 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "boto~=2.0", ] -test = [ - "opentelemetry-instrumentation-boto[instruments]", - "markupsafe==2.0.1", - "moto~=2.0", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] boto = "opentelemetry.instrumentation.boto:BotoInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/version.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/version.py +++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt new file mode 100644 index 0000000000..92c356ebe1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt @@ -0,0 +1,71 @@ +annotated-types==0.6.0 +asgiref==3.7.2 +attrs==23.2.0 +aws-sam-translator==1.85.0 +aws-xray-sdk==2.12.1 +boto==2.49.0 +boto3==1.34.44 +botocore==1.34.44 +certifi==2024.2.2 +cffi==1.16.0 +cfn-lint==0.85.2 +charset-normalizer==3.3.2 +cryptography==42.0.3 +Deprecated==1.2.14 +docker==7.0.0 +ecdsa==0.18.0 +graphql-core==3.2.3 +idna==3.6 +importlib-metadata==6.11.0 +importlib-resources==6.1.1 +iniconfig==2.0.0 +Jinja2==3.1.3 +jmespath==1.0.1 +jschema-to-python==1.2.3 +jsondiff==2.0.0 +jsonpatch==1.33 +jsonpickle==3.0.2 +jsonpointer==2.4 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 +junit-xml==1.9 +MarkupSafe==2.1.5 +moto==2.3.2 +mpmath==1.3.0 +networkx==3.1 +packaging==23.2 +pbr==6.0.0 +pkgutil_resolve_name==1.3.10 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pyasn1==0.5.1 +pycparser==2.21 +pydantic==2.6.1 +pydantic_core==2.16.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +python-jose==3.3.0 +pytz==2024.1 +PyYAML==6.0.1 +referencing==0.33.0 +regex==2023.12.25 +requests==2.31.0 +responses==0.25.0 +rpds-py==0.18.0 +rsa==4.9 +s3transfer==0.10.0 +sarif-om==1.0.4 +six==1.16.0 +sshpubkeys==3.3.1 +sympy==1.12 +tomli==2.0.1 +typing_extensions==4.9.0 +urllib3==1.26.18 +Werkzeug==3.0.1 +wrapt==1.16.0 +xmltodict==0.13.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-boto diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE b/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/pyproject.toml b/instrumentation/opentelemetry-instrumentation-boto3sqs/pyproject.toml index 89e1e112d8..2da67c9848 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] @@ -34,10 +34,6 @@ dependencies = [ instruments = [ "boto3 ~= 1.0", ] -test = [ - "opentelemetry-instrumentation-boto3sqs[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] boto3 = "opentelemetry.instrumentation.boto3sqs:Boto3SQSInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py index ee7f4a59a6..c0231f81e4 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py @@ -31,7 +31,7 @@ import logging from typing import Any, Collection, Dict, Generator, List, Mapping, Optional -import boto3 +import boto3.session import botocore.client from wrapt import wrap_function_wrapper @@ -382,7 +382,7 @@ def client_wrapper(wrapped, instance, args, kwargs): self._decorate_sqs(type(retval)) return retval - wrap_function_wrapper(boto3, "client", client_wrapper) + wrap_function_wrapper(boto3.session.Session, "client", client_wrapper) def _decorate_sqs(self, sqs_class: type) -> None: """ @@ -433,7 +433,7 @@ def _instrument(self, **kwargs: Dict[str, Any]) -> None: self._decorate_sqs(client_cls) def _uninstrument(self, **kwargs: Dict[str, Any]) -> None: - unwrap(boto3, "client") + unwrap(boto3.session.Session, "client") for client_cls in botocore.client.BaseClient.__subclasses__(): self._un_decorate_sqs(client_cls) diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt new file mode 100644 index 0000000000..2af3346e6d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt @@ -0,0 +1,24 @@ +asgiref==3.7.2 +attrs==23.2.0 +boto3==1.34.44 +botocore==1.34.44 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +jmespath==1.0.1 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +s3transfer==0.10.0 +six==1.16.0 +tomli==2.0.1 +typing_extensions==4.9.0 +urllib3==1.26.18 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-boto3sqs diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py index a6ca0e062b..7f7f00cf0a 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py @@ -20,7 +20,7 @@ import boto3 from botocore.awsrequest import AWSResponse -from wrapt import BoundFunctionWrapper, FunctionWrapper +from wrapt import BoundFunctionWrapper from opentelemetry.instrumentation.boto3sqs import ( Boto3SQSGetter, @@ -37,8 +37,17 @@ from opentelemetry.trace.span import Span, format_span_id, format_trace_id -def _make_sqs_client(): - return boto3.client( +def _make_sqs_client(*, session=False): + return (boto3.Session() if session else boto3).client( + "sqs", + region_name="us-east-1", + aws_access_key_id="dummy", + aws_secret_access_key="dummy", + ) + + +def _make_sqs_resource(*, session=False): + return (boto3.Session() if session else boto3).resource( "sqs", region_name="us-east-1", aws_access_key_id="dummy", @@ -48,7 +57,6 @@ def _make_sqs_client(): class TestBoto3SQSInstrumentor(TestCase): def _assert_instrumented(self, client): - self.assertIsInstance(boto3.client, FunctionWrapper) self.assertIsInstance(client.send_message, BoundFunctionWrapper) self.assertIsInstance(client.send_message_batch, BoundFunctionWrapper) self.assertIsInstance(client.receive_message, BoundFunctionWrapper) @@ -57,6 +65,17 @@ def _assert_instrumented(self, client): client.delete_message_batch, BoundFunctionWrapper ) + def _assert_uninstrumented(self, client): + self.assertNotIsInstance(client.send_message, BoundFunctionWrapper) + self.assertNotIsInstance( + client.send_message_batch, BoundFunctionWrapper + ) + self.assertNotIsInstance(client.receive_message, BoundFunctionWrapper) + self.assertNotIsInstance(client.delete_message, BoundFunctionWrapper) + self.assertNotIsInstance( + client.delete_message_batch, BoundFunctionWrapper + ) + @staticmethod @contextmanager def _active_instrumentor(): @@ -67,19 +86,48 @@ def _active_instrumentor(): Boto3SQSInstrumentor().uninstrument() def test_instrument_api_before_client_init(self) -> None: - with self._active_instrumentor(): - client = _make_sqs_client() - self._assert_instrumented(client) + for session in (False, True): + with self._active_instrumentor(): + client = _make_sqs_client(session=session) + self._assert_instrumented(client) + self._assert_uninstrumented(client) def test_instrument_api_after_client_init(self) -> None: - client = _make_sqs_client() - with self._active_instrumentor(): - self._assert_instrumented(client) + for session in (False, True): + client = _make_sqs_client(session=session) + with self._active_instrumentor(): + self._assert_instrumented(client) + self._assert_uninstrumented(client) def test_instrument_multiple_clients(self): - with self._active_instrumentor(): - self._assert_instrumented(_make_sqs_client()) - self._assert_instrumented(_make_sqs_client()) + for session in (False, True): + with self._active_instrumentor(): + self._assert_instrumented(_make_sqs_client(session=session)) + self._assert_instrumented(_make_sqs_client(session=session)) + + def test_instrument_api_before_resource_init(self) -> None: + for session in (False, True): + with self._active_instrumentor(): + sqs = _make_sqs_resource(session=session) + self._assert_instrumented(sqs.meta.client) + self._assert_uninstrumented(sqs.meta.client) + + def test_instrument_api_after_resource_init(self) -> None: + for session in (False, True): + sqs = _make_sqs_resource(session=session) + with self._active_instrumentor(): + self._assert_instrumented(sqs.meta.client) + self._assert_uninstrumented(sqs.meta.client) + + def test_instrument_multiple_resources(self): + for session in (False, True): + with self._active_instrumentor(): + self._assert_instrumented( + _make_sqs_resource(session=session).meta.client + ) + self._assert_instrumented( + _make_sqs_resource(session=session).meta.client + ) class TestBoto3SQSGetter(TestCase): diff --git a/instrumentation/opentelemetry-instrumentation-botocore/LICENSE b/instrumentation/opentelemetry-instrumentation-botocore/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-botocore/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-botocore/pyproject.toml b/instrumentation/opentelemetry-instrumentation-botocore/pyproject.toml index cd8add1aa7..7b0b34d255 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-botocore/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "opentelemetry-propagator-aws-xray == 1.0.1", ] @@ -34,13 +34,6 @@ dependencies = [ instruments = [ "botocore ~= 1.0", ] -test = [ - "opentelemetry-instrumentation-botocore[instruments]", - "markupsafe==2.0.1", - "botocore ~= 1.0, < 1.31.81", - "moto[all] ~= 2.2.6", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] botocore = "opentelemetry.instrumentation.botocore:BotocoreInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py index 299a37ab6c..57fb8b6794 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py @@ -62,9 +62,9 @@ def extract_attributes( cls, call_context: _AwsSdkCallContext, attributes: _AttributeMapT ): attributes[SpanAttributes.FAAS_INVOKED_PROVIDER] = "aws" - attributes[ - SpanAttributes.FAAS_INVOKED_NAME - ] = cls._parse_function_name(call_context) + attributes[SpanAttributes.FAAS_INVOKED_NAME] = ( + cls._parse_function_name(call_context) + ) attributes[SpanAttributes.FAAS_INVOKED_REGION] = call_context.region @classmethod diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py index aa55ae697f..9c3df3a2bc 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py @@ -76,9 +76,9 @@ def extract_attributes( destination_name, is_phone_number = cls._extract_destination_name( call_context ) - attributes[ - SpanAttributes.MESSAGING_DESTINATION_KIND - ] = MessagingDestinationKindValues.TOPIC.value + attributes[SpanAttributes.MESSAGING_DESTINATION_KIND] = ( + MessagingDestinationKindValues.TOPIC.value + ) attributes[SpanAttributes.MESSAGING_DESTINATION] = destination_name # TODO: Use SpanAttributes.MESSAGING_DESTINATION_NAME when opentelemetry-semantic-conventions 0.42b0 is released diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py index 777108cbb5..194e47b57f 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py @@ -35,9 +35,9 @@ def extract_attributes(self, attributes: _AttributeMapT): attributes[SpanAttributes.MESSAGING_SYSTEM] = "aws.sqs" attributes[SpanAttributes.MESSAGING_URL] = queue_url try: - attributes[ - SpanAttributes.MESSAGING_DESTINATION - ] = queue_url.split("/")[-1] + attributes[SpanAttributes.MESSAGING_DESTINATION] = ( + queue_url.split("/")[-1] + ) except IndexError: _logger.error( "Could not extract messaging destination from '%s'", diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/version.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/version.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt new file mode 100644 index 0000000000..9dcf9f9c0d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt @@ -0,0 +1,70 @@ +annotated-types==0.6.0 +asgiref==3.7.2 +attrs==23.2.0 +aws-sam-translator==1.85.0 +aws-xray-sdk==2.12.1 +boto3==1.28.80 +botocore==1.31.80 +certifi==2024.2.2 +cffi==1.16.0 +cfn-lint==0.85.2 +charset-normalizer==3.3.2 +cryptography==42.0.5 +Deprecated==1.2.14 +docker==7.0.0 +ecdsa==0.18.0 +idna==3.6 +importlib-metadata==6.11.0 +importlib-resources==6.1.1 +iniconfig==2.0.0 +Jinja2==3.1.3 +jmespath==1.0.1 +jschema-to-python==1.2.3 +jsondiff==2.0.0 +jsonpatch==1.33 +jsonpickle==3.0.3 +jsonpointer==2.4 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 +junit-xml==1.9 +MarkupSafe==2.0.1 +moto==2.2.20 +mpmath==1.3.0 +networkx==3.1 +packaging==23.2 +pbr==6.0.0 +pkgutil_resolve_name==1.3.10 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pyasn1==0.5.1 +pycparser==2.21 +pydantic==2.6.2 +pydantic_core==2.16.3 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +python-jose==3.3.0 +pytz==2024.1 +PyYAML==6.0.1 +referencing==0.33.0 +regex==2023.12.25 +requests==2.31.0 +responses==0.25.0 +rpds-py==0.18.0 +rsa==4.9 +s3transfer==0.7.0 +sarif-om==1.0.4 +six==1.16.0 +sshpubkeys==3.3.1 +sympy==1.12 +tomli==2.0.1 +typing_extensions==4.9.0 +urllib3==1.26.18 +Werkzeug==2.1.2 +wrapt==1.16.0 +xmltodict==0.13.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e propagator/opentelemetry-propagator-aws-xray +-e instrumentation/opentelemetry-instrumentation-botocore diff --git a/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE b/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-cassandra/pyproject.toml b/instrumentation/opentelemetry-instrumentation-cassandra/pyproject.toml index 9088332425..85f187922e 100644 --- a/instrumentation/opentelemetry-instrumentation-cassandra/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-cassandra/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] @@ -35,10 +35,6 @@ instruments = [ "cassandra-driver ~= 3.25", "scylla-driver ~= 3.25", ] -test = [ - "opentelemetry-instrumentation-cassandra[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] cassandra = "opentelemetry.instrumentation.cassandra:CassandraInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry/instrumentation/cassandra/version.py b/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry/instrumentation/cassandra/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry/instrumentation/cassandra/version.py +++ b/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry/instrumentation/cassandra/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt new file mode 100644 index 0000000000..f55190171d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt @@ -0,0 +1,23 @@ +asgiref==3.7.2 +attrs==23.2.0 +cassandra-driver==3.29.0 +click==8.1.7 +Deprecated==1.2.14 +geomet==0.2.1.post1 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +PyYAML==6.0.1 +scylla-driver==3.26.6 +six==1.16.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-cassandra diff --git a/instrumentation/opentelemetry-instrumentation-celery/LICENSE b/instrumentation/opentelemetry-instrumentation-celery/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-celery/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-celery/pyproject.toml b/instrumentation/opentelemetry-instrumentation-celery/pyproject.toml index ea866d4b4b..7b0027425f 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-celery/pyproject.toml @@ -25,19 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "celery >= 4.0, < 6.0", ] -test = [ - "opentelemetry-instrumentation-celery[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "pytest", -] [project.entry-points.opentelemetry_instrumentor] celery = "opentelemetry.instrumentation.celery:CeleryInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/version.py b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/version.py +++ b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt new file mode 100644 index 0000000000..98c661ca67 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt @@ -0,0 +1,32 @@ +amqp==5.2.0 +asgiref==3.7.2 +attrs==23.2.0 +backports.zoneinfo==0.2.1 +billiard==4.2.0 +celery==5.3.6 +click==8.1.7 +click-didyoumean==0.3.0 +click-plugins==1.1.1 +click-repl==0.3.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +kombu==5.3.5 +packaging==23.2 +pluggy==1.4.0 +prompt-toolkit==3.0.43 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +six==1.16.0 +tomli==2.0.1 +typing_extensions==4.9.0 +tzdata==2024.1 +vine==5.1.0 +wcwidth==0.2.13 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-celery diff --git a/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt new file mode 100644 index 0000000000..516e1a78b9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt @@ -0,0 +1,31 @@ +amqp==5.2.0 +asgiref==3.7.2 +attrs==23.2.0 +billiard==4.2.0 +celery==5.3.6 +click==8.1.7 +click-didyoumean==0.3.0 +click-plugins==1.1.1 +click-repl==0.3.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +kombu==5.3.5 +packaging==23.2 +pluggy==1.4.0 +prompt-toolkit==3.0.43 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +six==1.16.0 +tomli==2.0.1 +typing_extensions==4.9.0 +tzdata==2024.1 +vine==5.1.0 +wcwidth==0.2.13 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-celery diff --git a/instrumentation/opentelemetry-instrumentation-celery/tests/test_metrics.py b/instrumentation/opentelemetry-instrumentation-celery/tests/test_metrics.py index 01c9487ea8..f83759317b 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/tests/test_metrics.py +++ b/instrumentation/opentelemetry-instrumentation-celery/tests/test_metrics.py @@ -1,7 +1,10 @@ import threading import time +from platform import python_implementation from timeit import default_timer +from pytest import mark + from opentelemetry.instrumentation.celery import CeleryInstrumentor from opentelemetry.test.test_base import TestBase @@ -62,6 +65,9 @@ def test_basic_metric(self): est_value_delta=200, ) + @mark.skipif( + python_implementation() == "PyPy", reason="Fails randomly in pypy" + ) def test_metric_uninstrument(self): CeleryInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py b/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py index ed4dbb5b1d..3ac6a5a70c 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py +++ b/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py @@ -125,8 +125,9 @@ def test_task_raises(self): self.assertIn(SpanAttributes.EXCEPTION_STACKTRACE, event.attributes) - self.assertEqual( - event.attributes[SpanAttributes.EXCEPTION_TYPE], "CustomError" + # TODO: use plain assertEqual after 1.25 is released (https://github.com/open-telemetry/opentelemetry-python/pull/3837) + self.assertIn( + "CustomError", event.attributes[SpanAttributes.EXCEPTION_TYPE] ) self.assertEqual( diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE b/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/pyproject.toml b/instrumentation/opentelemetry-instrumentation-confluent-kafka/pyproject.toml index 4ded0836b2..9baeaeb40e 100644 --- a/instrumentation/opentelemetry-instrumentation-confluent-kafka/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/pyproject.toml @@ -21,6 +21,7 @@ classifiers = [ "Programming Language :: Python :: 3.8", ] dependencies = [ + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-api ~= 1.12", "wrapt >= 1.0.0, < 2.0.0", ] @@ -29,9 +30,6 @@ dependencies = [ instruments = [ "confluent-kafka >= 1.8.2, <= 2.3.0", ] -test = [ - "opentelemetry-instrumentation-confluent-kafka[instruments]", -] [project.entry-points.opentelemetry_instrumentor] confluent_kafka = "opentelemetry.instrumentation.confluent_kafka:ConfluentKafkaInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry/instrumentation/confluent_kafka/version.py b/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry/instrumentation/confluent_kafka/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry/instrumentation/confluent_kafka/version.py +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry/instrumentation/confluent_kafka/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt new file mode 100644 index 0000000000..be859a2ce1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +confluent-kafka==2.3.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-confluent-kafka diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE b/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml index 5ae0f09376..e726768535 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/version.py b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/version.py index 6340c1adfb..17627b21dc 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/version.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/version.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-django/LICENSE b/instrumentation/opentelemetry-instrumentation-django/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-django/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-django/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-django/pyproject.toml b/instrumentation/opentelemetry-instrumentation-django/pyproject.toml index 65be04cb69..c8869d7b29 100644 --- a/instrumentation/opentelemetry-instrumentation-django/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-django/pyproject.toml @@ -25,15 +25,15 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-wsgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-wsgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] asgi = [ - "opentelemetry-instrumentation-asgi == 0.45b0.dev", + "opentelemetry-instrumentation-asgi == 0.46b0.dev", ] instruments = [ "django >= 1.10", diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py index bc677a81cf..1b747fd2c0 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py @@ -163,9 +163,9 @@ class _DjangoMiddleware(MiddlewareMixin): _active_request_counter = None _otel_request_hook: Callable[[Span, HttpRequest], None] = None - _otel_response_hook: Callable[ - [Span, HttpRequest, HttpResponse], None - ] = None + _otel_response_hook: Callable[[Span, HttpRequest, HttpResponse], None] = ( + None + ) @staticmethod def _get_span_name(request): @@ -229,9 +229,9 @@ def process_request(self, request): ) duration_attrs = _parse_duration_attrs(attributes) - request.META[ - self._environ_active_request_attr_key - ] = active_requests_count_attrs + request.META[self._environ_active_request_attr_key] = ( + active_requests_count_attrs + ) request.META[self._environ_duration_attr_key] = duration_attrs self._active_request_counter.add(1, active_requests_count_attrs) if span.is_recording(): @@ -336,9 +336,9 @@ def process_response(self, request, response): self._environ_duration_attr_key, None ) if duration_attrs: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = response.status_code + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + response.status_code + ) request_start_time = request.META.pop(self._environ_timer_key, None) if activation and span: diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py index 30492a8be5..ef53d5dc38 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py @@ -83,20 +83,26 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T: sql = _add_sql_comment( sql, # Information about the controller. - controller=resolver_match.view_name - if resolver_match and with_controller - else None, + controller=( + resolver_match.view_name + if resolver_match and with_controller + else None + ), # route is the pattern that matched a request with a controller i.e. the regex # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.route # getattr() because the attribute doesn't exist in Django < 2.2. - route=getattr(resolver_match, "route", None) - if resolver_match and with_route - else None, + route=( + getattr(resolver_match, "route", None) + if resolver_match and with_route + else None + ), # app_name is the application namespace for the URL pattern that matches the URL. # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.app_name - app_name=(resolver_match.app_name or None) - if resolver_match and with_app_name - else None, + app_name=( + (resolver_match.app_name or None) + if resolver_match and with_app_name + else None + ), # Framework centric information. framework=f"django:{_django_version}" if with_framework else None, # Information about the database and driver. diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/version.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/version.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt index 116dc015ec..548db1b8e3 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt @@ -1,7 +1,7 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -Django==3.2.24 +Django==3.2.25 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt index ac3b40e16b..0970d2f253 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt @@ -2,7 +2,7 @@ asgiref==3.7.2 attrs==23.2.0 backports.zoneinfo==0.2.1 Deprecated==1.2.14 -Django==4.2.10 +Django==4.2.11 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt index 3bb32c4c6b..d853c05877 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt @@ -1,7 +1,7 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -Django==4.2.10 +Django==4.2.11 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index d7bb1e544f..63af1e6b86 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -155,9 +155,11 @@ def test_templated_route_get(self): self.assertEqual( span.name, - "GET ^route/(?P[0-9]{4})/template/$" - if DJANGO_2_2 - else "GET", + ( + "GET ^route/(?P[0-9]{4})/template/$" + if DJANGO_2_2 + else "GET" + ), ) self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) @@ -390,7 +392,7 @@ def response_hook(span, request, response): self.assertIsInstance(response_hook_args[2], HttpResponse) self.assertEqual(response_hook_args[2], response) - async def test_trace_parent(self): + def test_trace_parent(self): id_generator = RandomIdGenerator() trace_id = format_trace_id(id_generator.generate_trace_id()) span_id = format_span_id(id_generator.generate_span_id()) @@ -398,7 +400,7 @@ async def test_trace_parent(self): Client().get( "/span_name/1234/", - traceparent=traceparent_value, + HTTP_TRACEPARENT=traceparent_value, ) span = self.memory_exporter.get_finished_spans()[0] diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/views.py b/instrumentation/opentelemetry-instrumentation-django/tests/views.py index 452a7c0fdd..6310664100 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/views.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/views.py @@ -35,12 +35,12 @@ def response_with_custom_header(request): response = HttpResponse() response["custom-test-header-1"] = "test-header-value-1" response["custom-test-header-2"] = "test-header-value-2" - response[ - "my-custom-regex-header-1" - ] = "my-custom-regex-value-1,my-custom-regex-value-2" - response[ - "my-custom-regex-header-2" - ] = "my-custom-regex-value-3,my-custom-regex-value-4" + response["my-custom-regex-header-1"] = ( + "my-custom-regex-value-1,my-custom-regex-value-2" + ) + response["my-custom-regex-header-2"] = ( + "my-custom-regex-value-3,my-custom-regex-value-4" + ) response["my-secret-header"] = "my-secret-value" return response diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE b/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml b/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml index 987cfb17c1..f5ba221b7f 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml @@ -25,14 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] [project.optional-dependencies] instruments = [ - "elasticsearch >= 2.0", + "elasticsearch >= 6.0", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py index dd72a5235e..ceb50cac56 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py @@ -245,9 +245,11 @@ def wrapper(wrapped, _, args, kwargs): if method: attributes["elasticsearch.method"] = method if body: - attributes[SpanAttributes.DB_STATEMENT] = sanitize_body( - body - ) + # Don't set db.statement for bulk requests, as it can be very large + if isinstance(body, dict): + attributes[SpanAttributes.DB_STATEMENT] = ( + sanitize_body(body) + ) if params: attributes["elasticsearch.params"] = str(params) if doc_id: diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/version.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/version.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt index 216d1c0b02..054c8a8047 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt @@ -1,8 +1,8 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -elasticsearch==2.4.1 -elasticsearch-dsl==2.2.0 +elasticsearch==6.8.2 +elasticsearch-dsl==6.4.0 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt index 2c51c87508..efa05fd7ff 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt @@ -1,8 +1,8 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -elasticsearch==5.5.3 -elasticsearch-dsl==5.4.0 +elasticsearch==7.17.9 +elasticsearch-dsl==7.4.1 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 @@ -15,7 +15,7 @@ python-dateutil==2.8.2 six==1.16.0 tomli==2.0.1 typing_extensions==4.10.0 -urllib3==2.2.1 +urllib3==1.26.18 wrapt==1.16.0 zipp==3.17.0 -e opentelemetry-instrumentation diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py deleted file mode 100644 index 008a95d671..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py +++ /dev/null @@ -1,33 +0,0 @@ -from elasticsearch_dsl import ( # pylint: disable=no-name-in-module - DocType, - String, -) - - -class Article(DocType): - title = String(analyzer="snowball", fields={"raw": String()}) - body = String(analyzer="snowball") - - class Meta: - index = "test-index" - - -dsl_create_statement = { - "mappings": { - "article": { - "properties": { - "title": { - "analyzer": "snowball", - "fields": {"raw": {"type": "string"}}, - "type": "string", - }, - "body": {"analyzer": "snowball", "type": "string"}, - } - } - }, - "settings": {"analysis": {}}, -} -dsl_index_result = (1, {}, '{"created": true}') -dsl_index_span_name = "Elasticsearch/test-index/article/2" -dsl_index_url = "/test-index/article/2" -dsl_search_method = "GET" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py deleted file mode 100644 index cf32d98863..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py +++ /dev/null @@ -1,33 +0,0 @@ -from elasticsearch_dsl import ( # pylint: disable=no-name-in-module - DocType, - Keyword, - Text, -) - - -class Article(DocType): - title = Text(analyzer="snowball", fields={"raw": Keyword()}) - body = Text(analyzer="snowball") - - class Meta: - index = "test-index" - - -dsl_create_statement = { - "mappings": { - "article": { - "properties": { - "title": { - "analyzer": "snowball", - "fields": {"raw": {"type": "keyword"}}, - "type": "text", - }, - "body": {"analyzer": "snowball", "type": "text"}, - } - } - }, -} -dsl_index_result = (1, {}, '{"created": true}') -dsl_index_span_name = "Elasticsearch/test-index/article/2" -dsl_index_url = "/test-index/article/2" -dsl_search_method = "GET" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py index a2d37a54a9..b22df18452 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py @@ -26,6 +26,6 @@ class Index: } } dsl_index_result = (1, {}, '{"result": "created"}') -dsl_index_span_name = "Elasticsearch/test-index/_doc/2" +dsl_index_span_name = "Elasticsearch/test-index/_doc/:id" dsl_index_url = "/test-index/_doc/2" dsl_search_method = "POST" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py index 0c84cf5cd6..690cbe3d4c 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py @@ -44,13 +44,28 @@ from . import helpers_es7 as helpers # pylint: disable=no-name-in-module elif major_version == 6: from . import helpers_es6 as helpers # pylint: disable=no-name-in-module -elif major_version == 5: - from . import helpers_es5 as helpers # pylint: disable=no-name-in-module -else: - from . import helpers_es2 as helpers # pylint: disable=no-name-in-module Article = helpers.Article +# pylint: disable=too-many-public-methods + + +def normalize_arguments(doc_type, body=None): + if major_version == 7: + return {"document": body} if body else {} + return ( + {"body": body, "doc_type": doc_type} + if body + else {"doc_type": doc_type} + ) + + +def get_elasticsearch_client(*args, **kwargs): + client = Elasticsearch(*args, **kwargs) + if major_version == 7: + client.transport._verified_elasticsearch = True + return client + @mock.patch( "elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request" @@ -81,10 +96,14 @@ def tearDown(self): ElasticsearchInstrumentor().uninstrument() def test_instrumentor(self, request_mock): - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") - es = Elasticsearch() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) @@ -99,20 +118,24 @@ def test_instrumentor(self, request_mock): # check that no spans are generated after uninstrument ElasticsearchInstrumentor().uninstrument() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) def test_span_not_recording(self, request_mock): - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") mock_tracer = mock.Mock() mock_span = mock.Mock() mock_span.is_recording.return_value = False mock_tracer.start_span.return_value = mock_span with mock.patch("opentelemetry.trace.get_tracer") as tracer: tracer.return_value = mock_tracer - Elasticsearch() + get_elasticsearch_client(hosts=["http://localhost:9200"]) self.assertFalse(mock_span.is_recording()) self.assertTrue(mock_span.is_recording.called) self.assertFalse(mock_span.set_attribute.called) @@ -124,7 +147,7 @@ def test_prefix_arg(self, request_mock): prefix = "prefix-from-env" ElasticsearchInstrumentor().uninstrument() ElasticsearchInstrumentor(span_name_prefix=prefix).instrument() - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") self._test_prefix(prefix) def test_prefix_env(self, request_mock): @@ -133,13 +156,17 @@ def test_prefix_env(self, request_mock): os.environ[env_var] = prefix ElasticsearchInstrumentor().uninstrument() ElasticsearchInstrumentor().instrument() - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") del os.environ[env_var] self._test_prefix(prefix) def _test_prefix(self, prefix): - es = Elasticsearch() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) @@ -152,8 +179,10 @@ def test_result_values(self, request_mock): {}, '{"found": false, "timed_out": true, "took": 7}', ) - es = Elasticsearch() - es.get(index="test-index", doc_type="_doc", id=1) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 + ) spans = self.get_finished_spans() @@ -173,14 +202,18 @@ def test_trace_error_unknown(self, request_mock): def test_trace_error_not_found(self, request_mock): msg = "record not found" exc = elasticsearch.exceptions.NotFoundError(404, msg) - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") request_mock.side_effect = exc self._test_trace_error(StatusCode.ERROR, exc) def _test_trace_error(self, code, exc): - es = Elasticsearch() + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) try: - es.get(index="test-index", doc_type="_doc", id=1) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=1, + ) except Exception: # pylint: disable=broad-except pass @@ -194,10 +227,14 @@ def _test_trace_error(self, code, exc): ) def test_parent(self, request_mock): - request_mock.return_value = (1, {}, {}) - es = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) with self.tracer.start_as_current_span("parent"): - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es.index( + index="sw", + **normalize_arguments(doc_type="_doc", body={"name": "adam"}), + id=1, + ) spans = self.get_finished_spans() self.assertEqual(len(spans), 2) @@ -208,8 +245,8 @@ def test_parent(self, request_mock): self.assertEqual(child.parent.span_id, parent.context.span_id) def test_multithread(self, request_mock): - request_mock.return_value = (1, {}, {}) - es = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) ev = threading.Event() # 1. Start tracing from thread-1; make thread-2 wait @@ -217,13 +254,21 @@ def test_multithread(self, request_mock): # 3. Check the spans got different parents, and are in the expected order. def target1(parent_span): with trace.use_span(parent_span): - es.get(index="test-index", doc_type="_doc", id=1) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=1, + ) ev.set() ev.wait() def target2(): ev.wait() - es.get(index="test-index", doc_type="_doc", id=2) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=2, + ) ev.set() with self.tracer.start_as_current_span("parent") as span: @@ -249,7 +294,7 @@ def target2(): def test_dsl_search(self, request_mock): request_mock.return_value = (1, {}, '{"hits": {"hits": []}}') - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) search = Search(using=client, index="test-index").filter( "term", author="testing" ) @@ -266,7 +311,7 @@ def test_dsl_search(self, request_mock): def test_dsl_search_sanitized(self, request_mock): request_mock.return_value = (1, {}, '{"hits": {"hits": []}}') - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) search = Search(using=client, index="test-index").filter( "term", author="testing" ) @@ -282,8 +327,8 @@ def test_dsl_search_sanitized(self, request_mock): ) def test_dsl_create(self, request_mock): - request_mock.return_value = (1, {}, {}) - client = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) Article.init(using=client) spans = self.get_finished_spans() @@ -309,8 +354,8 @@ def test_dsl_create(self, request_mock): ) def test_dsl_create_sanitized(self, request_mock): - request_mock.return_value = (1, {}, {}) - client = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) Article.init(using=client) spans = self.get_finished_spans() @@ -325,9 +370,9 @@ def test_dsl_create_sanitized(self, request_mock): ) def test_dsl_index(self, request_mock): - request_mock.return_value = helpers.dsl_index_result + request_mock.return_value = (1, {}, helpers.dsl_index_result[2]) - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) article = Article( meta={"id": 2}, title="About searching", @@ -376,11 +421,16 @@ def request_hook(span, method, url, kwargs): {}, '{"found": false, "timed_out": true, "took": 7}', ) - es = Elasticsearch() + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) index = "test-index" doc_id = 1 - kwargs = {"params": {"test": True}} - es.get(index=index, doc_type="_doc", id=doc_id, **kwargs) + kwargs = {"params": {"refresh": True, "realtime": True}} + es.get( + index=index, + id=doc_id, + **normalize_arguments(doc_type="_doc"), + **kwargs, + ) spans = self.get_finished_spans() @@ -388,12 +438,21 @@ def request_hook(span, method, url, kwargs): self.assertEqual( "GET", spans[0].attributes[request_hook_method_attribute] ) + expected_url = f"/{index}/_doc/{doc_id}" self.assertEqual( - f"/{index}/_doc/{doc_id}", + expected_url, spans[0].attributes[request_hook_url_attribute], ) + + if major_version == 7: + expected_kwargs = { + **kwargs, + "headers": {"accept": "application/json"}, + } + else: + expected_kwargs = {**kwargs} self.assertEqual( - json.dumps(kwargs), + json.dumps(expected_kwargs), spans[0].attributes[request_hook_kwargs_attribute], ) @@ -433,13 +492,11 @@ def response_hook(span, response): }, } - request_mock.return_value = ( - 1, - {}, - json.dumps(response_payload), + request_mock.return_value = (1, {}, json.dumps(response_payload)) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 ) - es = Elasticsearch() - es.get(index="test-index", doc_type="_doc", id=1) spans = self.get_finished_spans() @@ -455,13 +512,11 @@ def test_no_op_tracer_provider(self, request_mock): tracer_provider=trace.NoOpTracerProvider() ) response_payload = '{"found": false, "timed_out": true, "took": 7}' - request_mock.return_value = ( - 1, - {}, - response_payload, + request_mock.return_value = (1, {}, response_payload) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + res = es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 ) - es = Elasticsearch() - res = es.get(index="test-index", doc_type="_doc", id=1) self.assertEqual( res.get("found"), json.loads(response_payload).get("found") ) @@ -486,3 +541,35 @@ def test_body_sanitization(self, _): sanitize_body(json.dumps(sanitization_queries.interval_query)), str(sanitization_queries.interval_query_sanitized), ) + + def test_bulk(self, request_mock): + request_mock.return_value = (1, {}, "{}") + + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.bulk( + body=[ + { + "_op_type": "index", + "_index": "sw", + "_doc_type": "_doc", + "_id": 1, + "doc": {"name": "adam"}, + }, + { + "_op_type": "index", + "_index": "sw", + "_doc_type": "_doc", + "_id": 1, + "doc": {"name": "adam"}, + }, + ] + ) + + spans_list = self.get_finished_spans() + self.assertEqual(len(spans_list), 1) + span = spans_list[0] + + # Check version and name in span's instrumentation info + self.assertEqualSpanInstrumentationInfo( + span, opentelemetry.instrumentation.elasticsearch + ) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/LICENSE b/instrumentation/opentelemetry-instrumentation-falcon/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-falcon/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-falcon/pyproject.toml b/instrumentation/opentelemetry-instrumentation-falcon/pyproject.toml index dab9534bf9..93787a010d 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-falcon/pyproject.toml @@ -25,10 +25,10 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-wsgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-wsgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "packaging >= 20.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 06a550cf3f..79c9a0cf0f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -382,9 +382,9 @@ def _start_response(status, response_headers, *args, **kwargs): raise finally: if span.is_recording(): - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + ) duration = max(round((default_timer() - start) * 1000), 0) self.duration_histogram.record(duration, duration_attrs) self.active_requests_counter.add(-1, active_requests_count_attrs) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/version.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/version.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 2245dbfd80..bf7f1d4f49 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -16,21 +16,21 @@ from unittest.mock import Mock, patch import pytest -from falcon import __version__ as _falcon_verison +from falcon import __version__ as _falcon_version from falcon import testing from packaging import version as package_version from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.falcon import FalconInstrumentor from opentelemetry.instrumentation.propagators import ( TraceResponsePropagator, get_global_response_propagator, set_global_response_propagator, ) -from opentelemetry.instrumentation.wsgi import ( - _active_requests_count_attrs, - _duration_attrs, -) from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -53,8 +53,8 @@ "http.server.duration", ] _recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, } @@ -125,7 +125,7 @@ def _test_method(self, method): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", "falcon.resource": "HelloWorldResource", SpanAttributes.HTTP_STATUS_CODE: 201, @@ -156,7 +156,7 @@ def test_404(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", SpanAttributes.HTTP_STATUS_CODE: 404, }, @@ -193,7 +193,7 @@ def test_500(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", SpanAttributes.HTTP_STATUS_CODE: 500, }, @@ -226,7 +226,7 @@ def test_url_template(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", "falcon.resource": "UserResource", SpanAttributes.HTTP_STATUS_CODE: 200, @@ -336,6 +336,7 @@ def test_falcon_metric_values(self): "http.flavor": "1.1", "http.server_name": "falconframework.org", "net.host.port": 80, + "net.host.name": "falconframework.org", "http.status_code": 404, } expected_requests_count_attributes = { @@ -344,6 +345,8 @@ def test_falcon_metric_values(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "falconframework.org", + "net.host.name": "falconframework.org", + "net.host.port": 80, } start = default_timer() self.client().simulate_get("/hello/756") @@ -523,7 +526,7 @@ def test_custom_request_header_not_added_in_internal_span(self): self.assertNotIn(key, span.attributes) @pytest.mark.skipif( - condition=package_version.parse(_falcon_verison) + condition=package_version.parse(_falcon_version) < package_version.parse("2.0.0"), reason="falcon<2 does not implement custom response headers", ) @@ -558,7 +561,7 @@ def test_custom_response_header_added_in_server_span(self): self.assertNotIn(key, span.attributes) @pytest.mark.skipif( - condition=package_version.parse(_falcon_verison) + condition=package_version.parse(_falcon_version) < package_version.parse("2.0.0"), reason="falcon<2 does not implement custom response headers", ) diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE b/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml index 89f1c77e43..0e11179de2 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml @@ -25,10 +25,10 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-asgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-asgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/version.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/version.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-flask/LICENSE b/instrumentation/opentelemetry-instrumentation-flask/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-flask/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml b/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml index 8e0dd1f858..2bc1335a51 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml @@ -25,10 +25,10 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-wsgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-wsgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "packaging >= 21.0", "importlib-metadata >= 4.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index ba1031655e..f2e0ee34cc 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -250,6 +250,15 @@ def response_hook(span: Span, status: str, response_headers: List): import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import context, trace +from opentelemetry.instrumentation._semconv import ( + _METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + _get_schema_url, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _OpenTelemetryStabilitySignalType, + _report_new, + _report_old, +) from opentelemetry.instrumentation.flask.package import _instruments from opentelemetry.instrumentation.flask.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -260,7 +269,11 @@ def response_hook(span: Span, status: str, response_headers: List): from opentelemetry.metrics import get_meter from opentelemetry.semconv.metrics import MetricInstruments from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.util.http import get_excluded_urls, parse_excluded_urls +from opentelemetry.util.http import ( + get_excluded_urls, + parse_excluded_urls, + sanitize_method, +) _logger = getLogger(__name__) @@ -286,8 +299,13 @@ def _request_ctx_ref() -> weakref.ReferenceType: def get_default_span_name(): + method = sanitize_method( + flask.request.environ.get("REQUEST_METHOD", "").strip() + ) + if method == "_OTHER": + method = "HTTP" try: - span_name = flask.request.url_rule.rule + span_name = f"{method} {flask.request.url_rule.rule}" except AttributeError: span_name = otel_wsgi.get_default_span_name(flask.request.environ) return span_name @@ -296,9 +314,11 @@ def get_default_span_name(): def _rewrapped_app( wsgi_app, active_requests_counter, - duration_histogram, + duration_histogram_old=None, response_hook=None, excluded_urls=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, + duration_histogram_new=None, ): def _wrapped_app(wrapped_app_environ, start_response): # We want to measure the time for route matching, etc. @@ -307,11 +327,16 @@ def _wrapped_app(wrapped_app_environ, start_response): # we better avoid it. wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = time_ns() start = default_timer() - attributes = otel_wsgi.collect_request_attributes(wrapped_app_environ) + attributes = otel_wsgi.collect_request_attributes( + wrapped_app_environ, sem_conv_opt_in_mode + ) active_requests_count_attrs = ( - otel_wsgi._parse_active_request_count_attrs(attributes) + otel_wsgi._parse_active_request_count_attrs( + attributes, + sem_conv_opt_in_mode, + ) ) - duration_attrs = otel_wsgi._parse_duration_attrs(attributes) + active_requests_counter.add(1, active_requests_count_attrs) def _start_response(status, response_headers, *args, **kwargs): @@ -330,13 +355,12 @@ def _start_response(status, response_headers, *args, **kwargs): if span: otel_wsgi.add_response_attributes( - span, status, response_headers + span, + status, + response_headers, + attributes, + sem_conv_opt_in_mode, ) - status_code = otel_wsgi._parse_status_code(status) - if status_code is not None: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = status_code if ( span.is_recording() and span.kind == trace.SpanKind.SERVER @@ -357,8 +381,21 @@ def _start_response(status, response_headers, *args, **kwargs): return start_response(status, response_headers, *args, **kwargs) result = wsgi_app(wrapped_app_environ, _start_response) - duration = max(round((default_timer() - start) * 1000), 0) - duration_histogram.record(duration, duration_attrs) + duration_s = default_timer() - start + if duration_histogram_old: + duration_attrs_old = otel_wsgi._parse_duration_attrs( + attributes, _HTTPStabilityMode.DEFAULT + ) + duration_histogram_old.record( + max(round(duration_s * 1000), 0), duration_attrs_old + ) + if duration_histogram_new: + duration_attrs_new = otel_wsgi._parse_duration_attrs( + attributes, _HTTPStabilityMode.HTTP + ) + duration_histogram_new.record( + max(duration_s, 0), duration_attrs_new + ) active_requests_counter.add(-1, active_requests_count_attrs) return result @@ -371,6 +408,7 @@ def _wrapped_before_request( excluded_urls=None, enable_commenter=True, commenter_options=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, ): def _before_request(): if excluded_urls and excluded_urls.url_disabled(flask.request.url): @@ -379,7 +417,8 @@ def _before_request(): span_name = get_default_span_name() attributes = otel_wsgi.collect_request_attributes( - flask_request_environ + flask_request_environ, + sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) if flask.request.url_rule: # For 404 that result from no route found, etc, we @@ -490,6 +529,7 @@ class _InstrumentedFlask(flask.Flask): _enable_commenter = True _commenter_options = None _meter_provider = None + _sem_conv_opt_in_mode = _HTTPStabilityMode.DEFAULT def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -503,11 +543,20 @@ def __init__(self, *args, **kwargs): _InstrumentedFlask._meter_provider, schema_url="https://opentelemetry.io/schemas/1.11.0", ) - duration_histogram = meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", - ) + duration_histogram_old = None + if _report_old(_InstrumentedFlask._sem_conv_opt_in_mode): + duration_histogram_old = meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + duration_histogram_new = None + if _report_new(_InstrumentedFlask._sem_conv_opt_in_mode): + duration_histogram_new = meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, unit="requests", @@ -517,9 +566,11 @@ def __init__(self, *args, **kwargs): self.wsgi_app = _rewrapped_app( self.wsgi_app, active_requests_counter, - duration_histogram, + duration_histogram_old, _InstrumentedFlask._response_hook, excluded_urls=_InstrumentedFlask._excluded_urls, + sem_conv_opt_in_mode=_InstrumentedFlask._sem_conv_opt_in_mode, + duration_histogram_new=duration_histogram_new, ) tracer = trace.get_tracer( @@ -535,6 +586,7 @@ def __init__(self, *args, **kwargs): excluded_urls=_InstrumentedFlask._excluded_urls, enable_commenter=_InstrumentedFlask._enable_commenter, commenter_options=_InstrumentedFlask._commenter_options, + sem_conv_opt_in_mode=_InstrumentedFlask._sem_conv_opt_in_mode, ) self._before_request = _before_request self.before_request(_before_request) @@ -578,11 +630,19 @@ def _instrument(self, **kwargs): _InstrumentedFlask._commenter_options = commenter_options meter_provider = kwargs.get("meter_provider") _InstrumentedFlask._meter_provider = meter_provider + + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) + + _InstrumentedFlask._sem_conv_opt_in_mode = sem_conv_opt_in_mode + flask.Flask = _InstrumentedFlask def _uninstrument(self, **kwargs): flask.Flask = self._original_flask + # pylint: disable=too-many-locals @staticmethod def instrument_app( app, @@ -598,6 +658,11 @@ def instrument_app( app._is_instrumented_by_opentelemetry = False if not app._is_instrumented_by_opentelemetry: + # initialize semantic conventions opt-in if needed + _OpenTelemetrySemanticConventionStability._initialize() + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) excluded_urls = ( parse_excluded_urls(excluded_urls) if excluded_urls is not None @@ -607,33 +672,44 @@ def instrument_app( __name__, __version__, meter_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", - ) - duration_histogram = meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) + duration_histogram_old = None + if _report_old(sem_conv_opt_in_mode): + duration_histogram_old = meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + duration_histogram_new = None + if _report_new(sem_conv_opt_in_mode): + duration_histogram_new = meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, - unit="requests", - description="measures the number of concurrent HTTP requests that are currently in-flight", + unit="{request}", + description="Number of active HTTP server requests.", ) app._original_wsgi_app = app.wsgi_app app.wsgi_app = _rewrapped_app( app.wsgi_app, active_requests_counter, - duration_histogram, - response_hook, + duration_histogram_old, + response_hook=response_hook, excluded_urls=excluded_urls, + sem_conv_opt_in_mode=sem_conv_opt_in_mode, + duration_histogram_new=duration_histogram_new, ) tracer = trace.get_tracer( __name__, __version__, tracer_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) _before_request = _wrapped_before_request( @@ -641,9 +717,10 @@ def instrument_app( tracer, excluded_urls=excluded_urls, enable_commenter=enable_commenter, - commenter_options=commenter_options - if commenter_options - else {}, + commenter_options=( + commenter_options if commenter_options else {} + ), + sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) app._before_request = _before_request app.before_request(_before_request) diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py index d83adbede0..150ca0ca9e 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py @@ -16,3 +16,5 @@ _instruments = ("flask >= 1.0",) _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/version.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/version.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py index 3c8073f261..307ac3ccf0 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py @@ -76,15 +76,15 @@ def _custom_response_headers(): resp = flask.Response("test response") resp.headers["content-type"] = "text/plain; charset=utf-8" resp.headers["content-length"] = "13" - resp.headers[ - "my-custom-header" - ] = "my-custom-value-1,my-custom-header-2" - resp.headers[ - "my-custom-regex-header-1" - ] = "my-custom-regex-value-1,my-custom-regex-value-2" - resp.headers[ - "My-Custom-Regex-Header-2" - ] = "my-custom-regex-value-3,my-custom-regex-value-4" + resp.headers["my-custom-header"] = ( + "my-custom-value-1,my-custom-header-2" + ) + resp.headers["my-custom-regex-header-1"] = ( + "my-custom-regex-value-1,my-custom-regex-value-2" + ) + resp.headers["My-Custom-Regex-Header-2"] = ( + "my-custom-regex-value-3,my-custom-regex-value-4" + ) resp.headers["my-secret-header"] = "my-secret-value" return resp diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py index 96268de5e7..7a57d01c43 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py @@ -44,5 +44,5 @@ def test_copycontext(self): resp = client.get("/copy_context", headers={"x-req": "a-header"}) self.assertEqual(200, resp.status_code) - self.assertEqual("/copy_context", resp.json["span_name"]) + self.assertEqual("GET /copy_context", resp.json["span_name"]) self.assertEqual("a-header", resp.json["request_header"]) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index 16f4334108..86ff3a78cd 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -12,23 +12,29 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-lines from timeit import default_timer from unittest.mock import Mock, patch from flask import Flask, request from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _SPAN_ATTRIBUTES_ERROR_TYPE, + OTEL_SEMCONV_STABILITY_OPT_IN, + _OpenTelemetrySemanticConventionStability, + _server_active_requests_count_attrs_new, + _server_active_requests_count_attrs_old, + _server_duration_attrs_new, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.instrumentation.propagators import ( TraceResponsePropagator, get_global_response_propagator, set_global_response_propagator, ) -from opentelemetry.instrumentation.wsgi import ( - OpenTelemetryMiddleware, - _active_requests_count_attrs, - _duration_attrs, -) +from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -54,6 +60,7 @@ def expected_attributes(override_attributes): SpanAttributes.HTTP_SERVER_NAME: "localhost", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, + SpanAttributes.NET_HOST_NAME: "localhost", SpanAttributes.HTTP_HOST: "localhost", SpanAttributes.HTTP_TARGET: "/", SpanAttributes.HTTP_FLAVOR: "1.1", @@ -64,26 +71,71 @@ def expected_attributes(override_attributes): return default_attributes -_expected_metric_names = [ +def expected_attributes_new(override_attributes): + default_attributes = { + SpanAttributes.HTTP_REQUEST_METHOD: "GET", + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.SERVER_ADDRESS: "localhost", + SpanAttributes.URL_PATH: "/hello/123", + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.1", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200, + } + for key, val in override_attributes.items(): + default_attributes[key] = val + return default_attributes + + +_expected_metric_names_old = [ "http.server.active_requests", "http.server.duration", ] -_recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, +_expected_metric_names_new = [ + "http.server.active_requests", + "http.server.request.duration", +] +_recommended_metrics_attrs_old = { + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, +} +_recommended_metrics_attrs_new = { + "http.server.active_requests": _server_active_requests_count_attrs_new, + "http.server.request.duration": _server_duration_attrs_new, +} +_server_active_requests_count_attrs_both = ( + _server_active_requests_count_attrs_old +) +_server_active_requests_count_attrs_both.extend( + _server_active_requests_count_attrs_new +) +_recommended_metrics_attrs_both = { + "http.server.active_requests": _server_active_requests_count_attrs_both, + "http.server.duration": _server_duration_attrs_old, + "http.server.request.duration": _server_duration_attrs_new, } +# pylint: disable=too-many-public-methods class TestProgrammatic(InstrumentationTest, WsgiTestBase): def setUp(self): super().setUp() + test_name = "" + if hasattr(self, "_testMethodName"): + test_name = self._testMethodName + sem_conv_mode = "default" + if "new_semconv" in test_name: + sem_conv_mode = "http" + elif "both_semconv" in test_name: + sem_conv_mode = "http/dup" + self.env_patch = patch.dict( "os.environ", { - "OTEL_PYTHON_FLASK_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg" + "OTEL_PYTHON_FLASK_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg", + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) + _OpenTelemetrySemanticConventionStability._initialized = False self.env_patch.start() self.exclude_patch = patch( @@ -169,7 +221,45 @@ def test_simple(self): span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "/hello/") + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_simple_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.URL_SCHEME: "http", + } + ) + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_simple_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_TARGET: "/hello/123", + SpanAttributes.HTTP_ROUTE: "/hello/", + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) @@ -219,6 +309,53 @@ def test_404(self): self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) + def test_404_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.HTTP_REQUEST_METHOD: "POST", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 404, + SpanAttributes.URL_PATH: "/bye", + SpanAttributes.URL_SCHEME: "http", + } + ) + + resp = self.client.post("/bye") + self.assertEqual(404, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "POST /bye") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_404_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_METHOD: "POST", + SpanAttributes.HTTP_TARGET: "/bye", + SpanAttributes.HTTP_STATUS_CODE: 404, + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.HTTP_REQUEST_METHOD: "POST", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 404, + SpanAttributes.URL_PATH: "/bye", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + + resp = self.client.post("/bye") + self.assertEqual(404, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "POST /bye") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + def test_internal_error(self): expected_attrs = expected_attributes( { @@ -232,7 +369,53 @@ def test_internal_error(self): resp.close() span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "/hello/") + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_internal_error_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.URL_PATH: "/hello/500", + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500, + _SPAN_ATTRIBUTES_ERROR_TYPE: "500", + SpanAttributes.URL_SCHEME: "http", + } + ) + resp = self.client.get("/hello/500") + self.assertEqual(500, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_internal_error_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_TARGET: "/hello/500", + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.HTTP_STATUS_CODE: 500, + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.URL_PATH: "/hello/500", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500, + _SPAN_ATTRIBUTES_ERROR_TYPE: "500", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + resp = self.client.get("/hello/500") + self.assertEqual(500, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) @@ -290,7 +473,7 @@ def test_flask_metrics(self): for scope_metric in resource_metric.scope_metrics: self.assertTrue(len(scope_metric.metrics) != 0) for metric in scope_metric.metrics: - self.assertIn(metric.name, _expected_metric_names) + self.assertIn(metric.name, _expected_metric_names_old) data_points = list(metric.data.data_points) self.assertEqual(len(data_points), 1) for point in data_points: @@ -304,7 +487,42 @@ def test_flask_metrics(self): number_data_point_seen = True for attr in point.attributes: self.assertIn( - attr, _recommended_attrs[metric.name] + attr, + _recommended_metrics_attrs_old[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_flask_metrics_new_semconv(self): + start = default_timer() + self.client.get("/hello/123") + self.client.get("/hello/321") + self.client.get("/hello/756") + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names_new) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_new[metric.name], ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) @@ -358,6 +576,7 @@ def test_basic_metric_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 200, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "GET", @@ -365,6 +584,25 @@ def test_basic_metric_success(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, + } + self._assert_basic_metric( + expected_duration_attributes, + expected_requests_count_attributes, + ) + + def test_basic_metric_success_new_semconv(self): + self.client.get("/hello/756") + expected_duration_attributes = { + "http.request.method": "GET", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 200, + } + expected_requests_count_attributes = { + "http.request.method": "GET", + "url.scheme": "http", } self._assert_basic_metric( expected_duration_attributes, @@ -374,20 +612,40 @@ def test_basic_metric_success(self): def test_basic_metric_nonstandard_http_method_success(self): self.client.open("/hello/756", method="NONSTANDARD") expected_duration_attributes = { - "http.method": "UNKNOWN", + "http.method": "_OTHER", "http.host": "localhost", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 405, + "net.host.name": "localhost", } expected_requests_count_attributes = { - "http.method": "UNKNOWN", + "http.method": "_OTHER", "http.host": "localhost", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, + } + self._assert_basic_metric( + expected_duration_attributes, + expected_requests_count_attributes, + ) + + def test_basic_metric_nonstandard_http_method_success_new_semconv(self): + self.client.open("/hello/756", method="NONSTANDARD") + expected_duration_attributes = { + "http.request.method": "_OTHER", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 405, + } + expected_requests_count_attributes = { + "http.request.method": "_OTHER", + "url.scheme": "http", } self._assert_basic_metric( expected_duration_attributes, @@ -400,23 +658,19 @@ def test_basic_metric_nonstandard_http_method_success(self): OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS: "1", }, ) - def test_basic_metric_nonstandard_http_method_allowed_success(self): + def test_basic_metric_nonstandard_http_method_allowed_success_new_semconv( + self, + ): self.client.open("/hello/756", method="NONSTANDARD") expected_duration_attributes = { - "http.method": "NONSTANDARD", - "http.host": "localhost", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "localhost", - "net.host.port": 80, - "http.status_code": 405, + "http.request.method": "NONSTANDARD", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 405, } expected_requests_count_attributes = { - "http.method": "NONSTANDARD", - "http.host": "localhost", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "localhost", + "http.request.method": "NONSTANDARD", + "url.scheme": "http", } self._assert_basic_metric( expected_duration_attributes, diff --git a/instrumentation/opentelemetry-instrumentation-grpc/LICENSE b/instrumentation/opentelemetry-instrumentation-grpc/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-grpc/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-grpc/pyproject.toml b/instrumentation/opentelemetry-instrumentation-grpc/pyproject.toml index 8373feaa40..750f76270a 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-grpc/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-sdk ~= 1.12", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] @@ -35,12 +35,6 @@ dependencies = [ instruments = [ "grpcio ~= 1.27", ] -test = [ - "opentelemetry-instrumentation-grpc[instruments]", - "opentelemetry-sdk ~= 1.12", - "opentelemetry-test-utils == 0.45b0.dev", - "protobuf ~= 3.13", -] [project.entry-points.opentelemetry_instrumentor] grpc_client = "opentelemetry.instrumentation.grpc:GrpcInstrumentorClient" diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py index 8fc992be73..9c8cc5cdf3 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py @@ -14,10 +14,9 @@ import functools import logging -from collections import OrderedDict import grpc -from grpc.aio import ClientCallDetails +from grpc.aio import ClientCallDetails, Metadata from opentelemetry.instrumentation.grpc._client import ( OpenTelemetryClientInterceptor, @@ -55,20 +54,19 @@ def callback(call): class _BaseAioClientInterceptor(OpenTelemetryClientInterceptor): @staticmethod - def propagate_trace_in_details(client_call_details): + def propagate_trace_in_details(client_call_details: ClientCallDetails): metadata = client_call_details.metadata if not metadata: - mutable_metadata = OrderedDict() + mutable_metadata = Metadata() else: - mutable_metadata = OrderedDict(metadata) + mutable_metadata = Metadata(*tuple(metadata)) inject(mutable_metadata, setter=_carrier_setter) - metadata = tuple(mutable_metadata.items()) return ClientCallDetails( client_call_details.method, client_call_details.timeout, - metadata, + mutable_metadata, client_call_details.credentials, client_call_details.wait_for_ready, ) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/version.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/version.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt new file mode 100644 index 0000000000..56d47af0df --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +grpcio==1.62.0 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +protobuf==3.20.3 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-asyncio==0.23.5 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-grpc diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py index 9658df1587..6c0b8eac21 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py @@ -21,7 +21,7 @@ async def simple_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - return await stub.SimpleMethod(request) + return await stub.SimpleMethod(request, metadata=(("key", "value"),)) async def client_streaming_method(stub, error=False): @@ -41,7 +41,7 @@ def server_streaming_method(stub, error=False): client_id=CLIENT_ID, request_data="error" if error else "data" ) - return stub.ServerStreamingMethod(request) + return stub.ServerStreamingMethod(request, metadata=(("key", "value"),)) def bidirectional_streaming_method(stub, error=False): @@ -53,4 +53,6 @@ def request_messages(): ) yield request - return stub.BidirectionalStreamingMethod(request_messages()) + return stub.BidirectionalStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py index 69222b37a4..67e7d0a625 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py @@ -21,14 +21,14 @@ def simple_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - stub.SimpleMethod(request) + stub.SimpleMethod(request, metadata=(("key", "value"),)) def simple_method_future(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - return stub.SimpleMethod.future(request) + return stub.SimpleMethod.future(request, metadata=(("key", "value"),)) def client_streaming_method(stub, error=False): @@ -40,14 +40,18 @@ def request_messages(): ) yield request - stub.ClientStreamingMethod(request_messages()) + stub.ClientStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) def server_streaming_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - response_iterator = stub.ServerStreamingMethod(request) + response_iterator = stub.ServerStreamingMethod( + request, metadata=(("key", "value"),) + ) list(response_iterator) @@ -59,6 +63,8 @@ def request_messages(): ) yield request - response_iterator = stub.BidirectionalStreamingMethod(request_messages()) + response_iterator = stub.BidirectionalStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) list(response_iterator) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py index ad3dcf3fe7..f00b5f82e7 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py @@ -142,7 +142,7 @@ (_message.Message,), { "DESCRIPTOR": _REQUEST, - "__module__": "test_server_pb2" + "__module__": "test_server_pb2", # @@protoc_insertion_point(class_scope:Request) }, ) @@ -153,7 +153,7 @@ (_message.Message,), { "DESCRIPTOR": _RESPONSE, - "__module__": "test_server_pb2" + "__module__": "test_server_pb2", # @@protoc_insertion_point(class_scope:Response) }, ) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py index 6b1006b8a3..21dbc44066 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py @@ -305,11 +305,10 @@ async def test_client_interceptor_trace_context_propagation(self): await simple_method(stub) metadata = recording_interceptor.recorded_details.metadata - assert len(metadata) == 2 - assert metadata[0][0] == "mock-traceid" - assert metadata[0][1] == "0" - assert metadata[1][0] == "mock-spanid" - assert metadata[1][1] == "0" + assert len(metadata) == 3 + assert metadata.get_all("key") == ["value"] + assert metadata.get_all("mock-traceid") == ["0"] + assert metadata.get_all("mock-spanid") == ["0"] finally: set_global_textmap(previous_propagator) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py index 2436aca40c..38759352b3 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py @@ -14,9 +14,6 @@ # pylint:disable=cyclic-import import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) import opentelemetry.instrumentation.grpc from opentelemetry import trace @@ -41,6 +38,7 @@ simple_method_future, ) from ._server import create_test_server +from .protobuf import test_server_pb2_grpc from .protobuf.test_server_pb2 import Request diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py index 9a9aefad59..b6ae975dff 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py @@ -17,9 +17,6 @@ from unittest import mock import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) import opentelemetry.instrumentation.grpc from opentelemetry import trace @@ -44,6 +41,7 @@ simple_method_future, ) from ._server import create_test_server +from .protobuf import test_server_pb2_grpc from .protobuf.test_server_pb2 import Request diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py index ca649f7bb1..aeecffc71c 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py @@ -13,9 +13,6 @@ # limitations under the License. import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) from opentelemetry import trace from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient @@ -23,6 +20,7 @@ from ._client import simple_method from ._server import create_test_server +from .protobuf import test_server_pb2_grpc # User defined interceptor. Is used in the tests along with the opentelemetry client interceptor. diff --git a/instrumentation/opentelemetry-instrumentation-httpx/LICENSE b/instrumentation/opentelemetry-instrumentation-httpx/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-httpx/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml b/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml index 1a4da4a520..e4e5575d96 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py index 53542e7ef3..7fcc7128be 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -270,7 +270,7 @@ def _extract_parameters(args, kwargs): # In httpx >= 0.20.0, handle_request receives a Request object request: httpx.Request = args[0] method = request.method.encode() - url = remove_url_credentials(str(request.url)) + url = httpx.URL(remove_url_credentials(str(request.url))) headers = request.headers stream = request.stream extensions = request.extensions @@ -433,9 +433,7 @@ async def __aexit__( ) -> None: await self._transport.__aexit__(exc_type, exc_value, traceback) - async def handle_async_request( - self, *args, **kwargs - ) -> typing.Union[ + async def handle_async_request(self, *args, **kwargs) -> typing.Union[ typing.Tuple[int, "Headers", httpx.AsyncByteStream, dict], httpx.Response, ]: diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/version.py b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/version.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py b/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py index b8d7fbb6b6..c3f668cafe 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py @@ -51,12 +51,18 @@ HTTP_RESPONSE_BODY = "http.response.body" +def _is_url_tuple(request: "RequestInfo"): + """Determine if request url format is for httpx versions < 0.20.0.""" + return isinstance(request[1], tuple) and len(request[1]) == 4 + + def _async_call(coro: typing.Coroutine) -> asyncio.Task: loop = asyncio.get_event_loop() return loop.run_until_complete(coro) def _response_hook(span, request: "RequestInfo", response: "ResponseInfo"): + assert _is_url_tuple(request) or isinstance(request.url, httpx.URL) span.set_attribute( HTTP_RESPONSE_BODY, b"".join(response[2]), @@ -66,6 +72,7 @@ def _response_hook(span, request: "RequestInfo", response: "ResponseInfo"): async def _async_response_hook( span: "Span", request: "RequestInfo", response: "ResponseInfo" ): + assert _is_url_tuple(request) or isinstance(request.url, httpx.URL) span.set_attribute( HTTP_RESPONSE_BODY, b"".join([part async for part in response[2]]), @@ -73,11 +80,13 @@ async def _async_response_hook( def _request_hook(span: "Span", request: "RequestInfo"): + assert _is_url_tuple(request) or isinstance(request.url, httpx.URL) url = httpx.URL(request[1]) span.update_name("GET" + str(url)) async def _async_request_hook(span: "Span", request: "RequestInfo"): + assert _is_url_tuple(request) or isinstance(request.url, httpx.URL) url = httpx.URL(request[1]) span.update_name("GET" + str(url)) diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE b/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/pyproject.toml b/instrumentation/opentelemetry-instrumentation-jinja2/pyproject.toml index c3648a2922..6284496ebd 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-jinja2/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] @@ -33,11 +33,6 @@ dependencies = [ instruments = [ "jinja2 >= 2.7, < 4.0", ] -test = [ - "opentelemetry-instrumentation-jinja2[instruments]", - "markupsafe==2.0.1", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] jinja2 = "opentelemetry.instrumentation.jinja2:Jinja2Instrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/version.py b/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/version.py +++ b/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt new file mode 100644 index 0000000000..d8ab59ac2d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +Jinja2==3.1.3 +MarkupSafe==2.0.1 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-jinja2 diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE b/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/pyproject.toml b/instrumentation/opentelemetry-instrumentation-kafka-python/pyproject.toml index b303a61a5c..580c076a82 100644 --- a/instrumentation/opentelemetry-instrumentation-kafka-python/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/pyproject.toml @@ -25,19 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.5", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "kafka-python >= 2.0", ] -test = [ - "opentelemetry-instrumentation-kafka-python[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "wrapt >= 1.0.0, < 2.0.0", -] [project.entry-points.opentelemetry_instrumentor] kafka = "opentelemetry.instrumentation.kafka:KafkaInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry/instrumentation/kafka/version.py b/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry/instrumentation/kafka/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry/instrumentation/kafka/version.py +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry/instrumentation/kafka/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt new file mode 100644 index 0000000000..96bef86dbe --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +kafka-python==2.0.2 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-kafka-python diff --git a/instrumentation/opentelemetry-instrumentation-logging/LICENSE b/instrumentation/opentelemetry-instrumentation-logging/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-logging/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-logging/pyproject.toml b/instrumentation/opentelemetry-instrumentation-logging/pyproject.toml index 518fdb0403..57572ce634 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-logging/pyproject.toml @@ -25,14 +25,11 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", ] [project.optional-dependencies] instruments = [] -test = [ - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] logging = "opentelemetry.instrumentation.logging:LoggingInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/version.py b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/version.py index 6340c1adfb..17627b21dc 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/version.py +++ b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/version.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt new file mode 100644 index 0000000000..f376796169 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt @@ -0,0 +1,17 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-logging diff --git a/instrumentation/opentelemetry-instrumentation-mysql/LICENSE b/instrumentation/opentelemetry-instrumentation-mysql/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-mysql/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-mysql/pyproject.toml b/instrumentation/opentelemetry-instrumentation-mysql/pyproject.toml index 7f7b703266..481748c007 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-mysql/pyproject.toml @@ -25,18 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "mysql-connector-python ~= 8.0", ] -test = [ - "opentelemetry-instrumentation-mysql[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] mysql = "opentelemetry.instrumentation.mysql:MySQLInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry/instrumentation/mysql/version.py b/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry/instrumentation/mysql/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry/instrumentation/mysql/version.py +++ b/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry/instrumentation/mysql/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt new file mode 100644 index 0000000000..f113b768b1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +mysql-connector-python==8.3.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-mysql diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE b/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml b/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml index 7646a9be2b..c9db02e22f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/version.py b/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/version.py +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry/instrumentation/mysqlclient/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-pika/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pika/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-pika/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pika/pyproject.toml index b11c9bbffc..a41b7297a8 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-pika/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-api ~= 1.5", "packaging >= 20.0", "wrapt >= 1.0.0, < 2.0.0", @@ -33,12 +34,6 @@ dependencies = [ instruments = [ "pika >= 0.12.0", ] -test = [ - "opentelemetry-instrumentation-pika[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "pytest", - "wrapt >= 1.0.0, < 2.0.0", -] [project.entry-points.opentelemetry_instrumentor] pika = "opentelemetry.instrumentation.pika:PikaInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py index c745462cf3..d9cec06525 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py @@ -77,6 +77,15 @@ def consume_hook(span: Span, body: bytes, properties: BasicProperties): PikaInstrumentor.instrument_channel(channel, publish_hook=publish_hook, consume_hook=consume_hook) +Consumer Instrumentation +------------------------ +For consumer instrumentation, pika supports two consuming modes: + +* Consumers using the `basic_consume` method which accepts a callback. This is supported for global instrumentation + (`PikaInstrumentor().instrument()`) as well channel specific instrumentation (`PikaInstrumentor().instrument_channel(channel)`) +* Consumers using the `consume` method which returns a generator over messages. This is supported for global + instrumentations only (`PikaInstrumentor().instrument()`) + API --- """ diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py index 56c78a85c3..f37f74e396 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py @@ -20,7 +20,10 @@ import wrapt from packaging import version from pika.adapters import BlockingConnection -from pika.adapters.blocking_connection import BlockingChannel +from pika.adapters.blocking_connection import ( + BlockingChannel, + _QueueConsumerGeneratorInfo, +) from opentelemetry import trace from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -153,9 +156,9 @@ def uninstrument_channel(channel: BlockingChannel) -> None: callback_attr = PikaInstrumentor.CONSUMER_CALLBACK_ATTR consumer_callback = getattr(client_info, callback_attr, None) if hasattr(consumer_callback, "_original_callback"): - channel._consumer_infos[ - consumers_tag - ] = consumer_callback._original_callback + channel._consumer_infos[consumers_tag] = ( + consumer_callback._original_callback + ) PikaInstrumentor._uninstrument_channel_functions(channel) def _decorate_channel_function( @@ -191,6 +194,24 @@ def wrapper(wrapped, instance, args, kwargs): wrapt.wrap_function_wrapper(channel, "basic_consume", wrapper) + @staticmethod + def _decorate_queue_consumer_generator( + tracer_provider: Optional[TracerProvider], + consume_hook: utils.HookT = utils.dummy_callback, + ) -> None: + tracer = trace.get_tracer(__name__, __version__, tracer_provider) + + def wrapper(wrapped, instance, args, kwargs): + res = wrapped(*args, **kwargs) + instance.pending_events = utils.ReadyMessagesDequeProxy( + instance.pending_events, instance, tracer, consume_hook + ) + return res + + wrapt.wrap_function_wrapper( + _QueueConsumerGeneratorInfo, "__init__", wrapper + ) + def _instrument(self, **kwargs: Dict[str, Any]) -> None: tracer_provider: TracerProvider = kwargs.get("tracer_provider", None) publish_hook: utils.HookT = kwargs.get( @@ -207,10 +228,15 @@ def _instrument(self, **kwargs: Dict[str, Any]) -> None: consume_hook=consume_hook, ) + self._decorate_queue_consumer_generator( + tracer_provider, consume_hook=consume_hook + ) + def _uninstrument(self, **kwargs: Dict[str, Any]) -> None: if hasattr(self, "__opentelemetry_tracer_provider"): delattr(self, "__opentelemetry_tracer_provider") unwrap(BlockingConnection, "channel") + unwrap(_QueueConsumerGeneratorInfo, "__init__") def instrumentation_dependencies(self) -> Collection[str]: return _instruments diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py index 6dab4fdfa9..2b4d1204ea 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py @@ -1,8 +1,13 @@ from logging import getLogger from typing import Any, Callable, List, Optional +from pika.adapters.blocking_connection import ( + _ConsumerDeliveryEvt, + _QueueConsumerGeneratorInfo, +) from pika.channel import Channel from pika.spec import Basic, BasicProperties +from wrapt import ObjectProxy from opentelemetry import context, propagate, trace from opentelemetry.instrumentation.utils import is_instrumentation_enabled @@ -33,8 +38,7 @@ def keys(self, carrier: CarrierT) -> List[str]: HookT = Callable[[Span, bytes, BasicProperties], None] -def dummy_callback(span: Span, body: bytes, properties: BasicProperties): - ... +def dummy_callback(span: Span, body: bytes, properties: BasicProperties): ... def _decorate_callback( @@ -61,9 +65,9 @@ def decorated_callback( tracer, channel, properties, - destination=method.exchange - if method.exchange - else method.routing_key, + destination=( + method.exchange if method.exchange else method.routing_key + ), span_kind=SpanKind.CONSUMER, task_name=task_name, operation=MessagingOperationValues.RECEIVE, @@ -128,7 +132,7 @@ def decorated_function( def _get_span( tracer: Tracer, - channel: Channel, + channel: Optional[Channel], properties: BasicProperties, task_name: str, destination: str, @@ -157,7 +161,7 @@ def _generate_span_name( def _enrich_span( span: Span, - channel: Channel, + channel: Optional[Channel], properties: BasicProperties, task_destination: str, operation: Optional[MessagingOperationValues] = None, @@ -176,6 +180,8 @@ def _enrich_span( span.set_attribute( SpanAttributes.MESSAGING_CONVERSATION_ID, properties.correlation_id ) + if not channel: + return if not hasattr(channel.connection, "params"): span.set_attribute( SpanAttributes.NET_PEER_NAME, channel.connection._impl.params.host @@ -190,3 +196,77 @@ def _enrich_span( span.set_attribute( SpanAttributes.NET_PEER_PORT, channel.connection.params.port ) + + +# pylint:disable=abstract-method +class ReadyMessagesDequeProxy(ObjectProxy): + def __init__( + self, + wrapped, + queue_consumer_generator: _QueueConsumerGeneratorInfo, + tracer: Optional[Tracer], + consume_hook: HookT = dummy_callback, + ): + super().__init__(wrapped) + self._self_active_token = None + self._self_tracer = tracer + self._self_consume_hook = consume_hook + self._self_queue_consumer_generator = queue_consumer_generator + + def popleft(self, *args, **kwargs): + try: + # end active context if exists + if self._self_active_token: + context.detach(self._self_active_token) + except Exception as inst_exception: # pylint: disable=W0703 + _LOG.exception(inst_exception) + + evt = self.__wrapped__.popleft(*args, **kwargs) + + try: + # If a new message was received, create a span and set as active context + if isinstance(evt, _ConsumerDeliveryEvt): + method = evt.method + properties = evt.properties + if not properties: + properties = BasicProperties(headers={}) + if properties.headers is None: + properties.headers = {} + ctx = propagate.extract( + properties.headers, getter=_pika_getter + ) + if not ctx: + ctx = context.get_current() + message_ctx_token = context.attach(ctx) + span = _get_span( + self._self_tracer, + None, + properties, + destination=( + method.exchange + if method.exchange + else method.routing_key + ), + span_kind=SpanKind.CONSUMER, + task_name=self._self_queue_consumer_generator.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + try: + context.detach(message_ctx_token) + self._self_active_token = context.attach( + trace.set_span_in_context(span) + ) + self._self_consume_hook(span, evt.body, properties) + except Exception as hook_exception: # pylint: disable=W0703 + _LOG.exception(hook_exception) + finally: + # We must end the span here, because the next place we can hook + # is not the end of the user code, but only when the next message + # arrives. we still set this span's context as the active context + # so spans created by user code that handles this message will be + # children of this one. + span.end() + except Exception as inst_exception: # pylint: disable=W0703 + _LOG.exception(inst_exception) + + return evt diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/version.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/version.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt new file mode 100644 index 0000000000..fb3c6def5a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pika==0.13.1 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-pika diff --git a/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt new file mode 100644 index 0000000000..d3ce673dab --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pika==1.3.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-pika diff --git a/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py b/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py index 6e154c04f9..ad519c4a35 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py @@ -14,6 +14,7 @@ from unittest import TestCase, mock from pika.adapters import BlockingConnection +from pika.adapters.blocking_connection import _QueueConsumerGeneratorInfo from pika.channel import Channel from wrapt import BoundFunctionWrapper @@ -21,7 +22,10 @@ from opentelemetry.instrumentation.pika.pika_instrumentor import ( _consumer_callback_attribute_name, ) -from opentelemetry.instrumentation.pika.utils import dummy_callback +from opentelemetry.instrumentation.pika.utils import ( + ReadyMessagesDequeProxy, + dummy_callback, +) from opentelemetry.trace import Tracer @@ -40,13 +44,23 @@ def test_instrument_api(self) -> None: self.assertTrue( isinstance(BlockingConnection.channel, BoundFunctionWrapper) ) + self.assertTrue( + isinstance( + _QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper + ) + ) assert hasattr( instrumentation, "__opentelemetry_tracer_provider" ), "Tracer not stored for the object!" - instrumentation.uninstrument(channel=self.channel) + instrumentation.uninstrument() self.assertFalse( isinstance(BlockingConnection.channel, BoundFunctionWrapper) ) + self.assertFalse( + isinstance( + _QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper + ) + ) @mock.patch( "opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_channel_functions" @@ -57,7 +71,7 @@ def test_instrument_api(self) -> None: @mock.patch( "opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_blocking_channel_consumers" ) - def test_instrument( + def test_instrument_channel( self, instrument_blocking_channel_consumers: mock.MagicMock, instrument_basic_consume: mock.MagicMock, @@ -110,6 +124,23 @@ def test_instrument_basic_publish( self.channel.basic_publish, decorate_basic_publish.return_value ) + def test_instrument_queue_consumer_generator(self) -> None: + instrumentation = PikaInstrumentor() + instrumentation.instrument() + generator_info = _QueueConsumerGeneratorInfo( + params=("queue", False, False), consumer_tag="tag" + ) + self.assertTrue( + isinstance(generator_info.pending_events, ReadyMessagesDequeProxy) + ) + instrumentation.uninstrument() + generator_info = _QueueConsumerGeneratorInfo( + params=("queue", False, False), consumer_tag="tag" + ) + self.assertFalse( + isinstance(generator_info.pending_events, ReadyMessagesDequeProxy) + ) + def test_uninstrument_channel_functions(self) -> None: original_function = self.channel.basic_publish self.channel.basic_publish = mock.MagicMock() diff --git a/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py b/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py index ed33593389..d651ea64c9 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py +++ b/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py @@ -11,8 +11,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import collections from unittest import TestCase, mock +from pika.adapters.blocking_connection import ( + _ConsumerCancellationEvt, + _ConsumerDeliveryEvt, + _QueueConsumerGeneratorInfo, +) from pika.channel import Channel from pika.spec import Basic, BasicProperties @@ -448,3 +454,113 @@ def test_decorate_basic_publish_when_span_is_not_recording( exchange_name, routing_key, mock_body, properties, False ) self.assertEqual(retval, callback.return_value) + + # pylint: disable=too-many-statements + @mock.patch("opentelemetry.instrumentation.pika.utils._get_span") + @mock.patch("opentelemetry.propagate.extract") + @mock.patch("opentelemetry.context.detach") + @mock.patch("opentelemetry.context.attach") + @mock.patch("opentelemetry.context.get_current") + def test_decorate_deque_proxy( + self, + context_get_current: mock.MagicMock, + context_attach: mock.MagicMock, + context_detach: mock.MagicMock, + extract: mock.MagicMock, + get_span: mock.MagicMock, + ) -> None: + returned_span = mock.MagicMock() + get_span.return_value = returned_span + consume_hook = mock.MagicMock() + tracer = mock.MagicMock() + generator_info = mock.MagicMock( + spec=_QueueConsumerGeneratorInfo, + pending_events=mock.MagicMock(spec=collections.deque), + consumer_tag="mock_task_name", + ) + method = mock.MagicMock(spec=Basic.Deliver) + method.exchange = "test_exchange" + properties = mock.MagicMock() + evt = _ConsumerDeliveryEvt(method, properties, b"mock_body") + generator_info.pending_events.popleft.return_value = evt + proxy = utils.ReadyMessagesDequeProxy( + generator_info.pending_events, generator_info, tracer, consume_hook + ) + + # First call (no detach cleanup) + res = proxy.popleft() + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_called_once_with( + properties.headers, getter=utils._pika_getter + ) + context_get_current.assert_called_once() + self.assertEqual(context_attach.call_count, 2) + self.assertEqual(context_detach.call_count, 1) + get_span.assert_called_once_with( + tracer, + None, + properties, + destination=method.exchange, + span_kind=SpanKind.CONSUMER, + task_name=generator_info.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + consume_hook.assert_called_once() + returned_span.end.assert_called_once() + + generator_info.pending_events.reset_mock() + extract.reset_mock() + context_get_current.reset_mock() + get_span.reset_mock() + context_attach.reset_mock() + context_detach.reset_mock() + returned_span.end.reset_mock() + consume_hook.reset_mock() + + # Second call (has detach cleanup) + res = proxy.popleft() + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_called_once_with( + properties.headers, getter=utils._pika_getter + ) + context_get_current.assert_called_once() + self.assertEqual(context_attach.call_count, 2) + self.assertEqual(context_detach.call_count, 2) + get_span.assert_called_once_with( + tracer, + None, + properties, + destination=method.exchange, + span_kind=SpanKind.CONSUMER, + task_name=generator_info.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + consume_hook.assert_called_once() + returned_span.end.assert_called_once() + generator_info.pending_events.reset_mock() + + extract.reset_mock() + context_get_current.reset_mock() + get_span.reset_mock() + context_attach.reset_mock() + context_detach.reset_mock() + returned_span.end.reset_mock() + consume_hook.reset_mock() + + # Third call (cancellation event) + evt = _ConsumerCancellationEvt("") + generator_info.pending_events.popleft.return_value = evt + + res = proxy.popleft() + + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_not_called() + context_get_current.not_called() + context_detach.assert_called_once() + context_attach.assert_not_called() + get_span.assert_not_called() + consume_hook.assert_not_called() + returned_span.end.assert_not_called() diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE b/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/pyproject.toml b/instrumentation/opentelemetry-instrumentation-psycopg/pyproject.toml index a5a4da0b59..d2328035fb 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-psycopg/pyproject.toml @@ -26,18 +26,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "psycopg >= 3.1.0", ] -test = [ - "opentelemetry-instrumentation-psycopg[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] psycopg = "opentelemetry.instrumentation.psycopg:PsycopgInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py index ab473c2fe4..5d7054151a 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py @@ -105,8 +105,13 @@ import typing from typing import Collection -import psycopg -from psycopg import Cursor as pg_cursor # pylint: disable=no-name-in-module +import psycopg # pylint: disable=import-self +from psycopg import ( + AsyncCursor as pg_async_cursor, # pylint: disable=import-self,no-name-in-module +) +from psycopg import ( + Cursor as pg_cursor, # pylint: disable=no-name-in-module,import-self +) from psycopg.sql import Composed # pylint: disable=no-name-in-module from opentelemetry.instrumentation import dbapi @@ -151,9 +156,40 @@ def _instrument(self, **kwargs): commenter_options=commenter_options, ) + dbapi.wrap_connect( + __name__, + psycopg.Connection, # pylint: disable=no-member + "connect", + self._DATABASE_SYSTEM, + self._CONNECTION_ATTRIBUTES, + version=__version__, + tracer_provider=tracer_provider, + db_api_integration_factory=DatabaseApiIntegration, + enable_commenter=enable_sqlcommenter, + commenter_options=commenter_options, + ) + dbapi.wrap_connect( + __name__, + psycopg.AsyncConnection, # pylint: disable=no-member + "connect", + self._DATABASE_SYSTEM, + self._CONNECTION_ATTRIBUTES, + version=__version__, + tracer_provider=tracer_provider, + db_api_integration_factory=DatabaseApiAsyncIntegration, + enable_commenter=enable_sqlcommenter, + commenter_options=commenter_options, + ) + def _uninstrument(self, **kwargs): """ "Disable Psycopg instrumentation""" - dbapi.unwrap_connect(psycopg, "connect") + dbapi.unwrap_connect(psycopg, "connect") # pylint: disable=no-member + dbapi.unwrap_connect( + psycopg.Connection, "connect" # pylint: disable=no-member + ) + dbapi.unwrap_connect( + psycopg.AsyncConnection, "connect" # pylint: disable=no-member + ) # TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql @staticmethod @@ -204,6 +240,26 @@ def wrapped_connection( return connection +class DatabaseApiAsyncIntegration(dbapi.DatabaseApiIntegration): + async def wrapped_connection( + self, + connect_method: typing.Callable[..., typing.Any], + args: typing.Tuple[typing.Any, typing.Any], + kwargs: typing.Dict[typing.Any, typing.Any], + ): + """Add object proxy to connection object.""" + base_cursor_factory = kwargs.pop("cursor_factory", None) + new_factory_kwargs = {"db_api": self} + if base_cursor_factory: + new_factory_kwargs["base_factory"] = base_cursor_factory + kwargs["cursor_factory"] = _new_cursor_async_factory( + **new_factory_kwargs + ) + connection = await connect_method(*args, **kwargs) + self.get_connection_attributes(connection) + return connection + + class CursorTracer(dbapi.CursorTracer): def get_operation_name(self, cursor, args): if not args: @@ -259,3 +315,36 @@ def callproc(self, *args, **kwargs): ) return TracedCursorFactory + + +def _new_cursor_async_factory( + db_api=None, base_factory=None, tracer_provider=None +): + if not db_api: + db_api = DatabaseApiAsyncIntegration( + __name__, + PsycopgInstrumentor._DATABASE_SYSTEM, + connection_attributes=PsycopgInstrumentor._CONNECTION_ATTRIBUTES, + version=__version__, + tracer_provider=tracer_provider, + ) + base_factory = base_factory or pg_async_cursor + _cursor_tracer = CursorTracer(db_api) + + class TracedCursorAsyncFactory(base_factory): + async def execute(self, *args, **kwargs): + return await _cursor_tracer.traced_execution( + self, super().execute, *args, **kwargs + ) + + async def executemany(self, *args, **kwargs): + return await _cursor_tracer.traced_execution( + self, super().executemany, *args, **kwargs + ) + + async def callproc(self, *args, **kwargs): + return await _cursor_tracer.traced_execution( + self, super().callproc, *args, **kwargs + ) + + return TracedCursorAsyncFactory diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/version.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/version.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt new file mode 100644 index 0000000000..4b57cb1ca5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +backports.zoneinfo==0.2.1 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +psycopg==3.1.18 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-psycopg diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt new file mode 100644 index 0000000000..d449374047 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +psycopg==3.1.18 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-psycopg diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py b/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py index d5e4bc65f3..4fbcac6042 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/tests/test_psycopg_integration.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import types from unittest import mock @@ -45,6 +46,35 @@ def __exit__(self, *args): return self +class MockAsyncCursor: + def __init__(self, *args, **kwargs): + pass + + # pylint: disable=unused-argument, no-self-use + async def execute(self, query, params=None, throw_exception=False): + if throw_exception: + raise Exception("Test Exception") + + # pylint: disable=unused-argument, no-self-use + async def executemany(self, query, params=None, throw_exception=False): + if throw_exception: + raise Exception("Test Exception") + + # pylint: disable=unused-argument, no-self-use + async def callproc(self, query, params=None, throw_exception=False): + if throw_exception: + raise Exception("Test Exception") + + async def __aenter__(self, *args, **kwargs): + return self + + async def __aexit__(self, *args, **kwargs): + pass + + def close(self): + pass + + class MockConnection: commit = mock.MagicMock(spec=types.MethodType) commit.__name__ = "commit" @@ -64,22 +94,68 @@ def get_dsn_parameters(self): # pylint: disable=no-self-use return {"dbname": "test"} +class MockAsyncConnection: + commit = mock.MagicMock(spec=types.MethodType) + commit.__name__ = "commit" + + rollback = mock.MagicMock(spec=types.MethodType) + rollback.__name__ = "rollback" + + def __init__(self, *args, **kwargs): + self.cursor_factory = kwargs.pop("cursor_factory", None) + + @staticmethod + async def connect(*args, **kwargs): + return MockAsyncConnection(**kwargs) + + def cursor(self): + if self.cursor_factory: + cur = self.cursor_factory(self) + return cur + return MockAsyncCursor() + + def get_dsn_parameters(self): # pylint: disable=no-self-use + return {"dbname": "test"} + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + return mock.MagicMock(spec=types.MethodType) + + class TestPostgresqlIntegration(TestBase): def setUp(self): super().setUp() self.cursor_mock = mock.patch( "opentelemetry.instrumentation.psycopg.pg_cursor", MockCursor ) + self.cursor_async_mock = mock.patch( + "opentelemetry.instrumentation.psycopg.pg_async_cursor", + MockAsyncCursor, + ) self.connection_mock = mock.patch("psycopg.connect", MockConnection) + self.connection_sync_mock = mock.patch( + "psycopg.Connection.connect", MockConnection + ) + self.connection_async_mock = mock.patch( + "psycopg.AsyncConnection.connect", MockAsyncConnection.connect + ) self.cursor_mock.start() + self.cursor_async_mock.start() self.connection_mock.start() + self.connection_sync_mock.start() + self.connection_async_mock.start() def tearDown(self): super().tearDown() self.memory_exporter.clear() self.cursor_mock.stop() + self.cursor_async_mock.stop() self.connection_mock.stop() + self.connection_sync_mock.stop() + self.connection_async_mock.stop() with self.disable_logging(): PsycopgInstrumentor().uninstrument() @@ -114,6 +190,91 @@ def test_instrumentor(self): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) + # pylint: disable=unused-argument + def test_instrumentor_with_connection_class(self): + PsycopgInstrumentor().instrument() + + cnx = psycopg.Connection.connect(database="test") + + cursor = cnx.cursor() + + query = "SELECT * FROM test" + cursor.execute(query) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + span = spans_list[0] + + # Check version and name in span's instrumentation info + self.assertEqualSpanInstrumentationInfo( + span, opentelemetry.instrumentation.psycopg + ) + + # check that no spans are generated after uninstrument + PsycopgInstrumentor().uninstrument() + + cnx = psycopg.Connection.connect(database="test") + cursor = cnx.cursor() + query = "SELECT * FROM test" + cursor.execute(query) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + + async def test_wrap_async_connection_class_with_cursor(self): + PsycopgInstrumentor().instrument() + + async def test_async_connection(): + acnx = await psycopg.AsyncConnection.connect(database="test") + async with acnx as cnx: + async with cnx.cursor() as cursor: + await cursor.execute("SELECT * FROM test") + + asyncio.run(test_async_connection()) + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + span = spans_list[0] + + # Check version and name in span's instrumentation info + self.assertEqualSpanInstrumentationInfo( + span, opentelemetry.instrumentation.psycopg + ) + + # check that no spans are generated after uninstrument + PsycopgInstrumentor().uninstrument() + + asyncio.run(test_async_connection()) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + + # pylint: disable=unused-argument + async def test_instrumentor_with_async_connection_class(self): + PsycopgInstrumentor().instrument() + + async def test_async_connection(): + acnx = await psycopg.AsyncConnection.connect(database="test") + async with acnx as cnx: + await cnx.execute("SELECT * FROM test") + + asyncio.run(test_async_connection()) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + span = spans_list[0] + + # Check version and name in span's instrumentation info + self.assertEqualSpanInstrumentationInfo( + span, opentelemetry.instrumentation.psycopg + ) + + # check that no spans are generated after uninstrument + PsycopgInstrumentor().uninstrument() + asyncio.run(test_async_connection()) + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 1) + def test_span_name(self): PsycopgInstrumentor().instrument() @@ -140,6 +301,33 @@ def test_span_name(self): self.assertEqual(spans_list[4].name, "query") self.assertEqual(spans_list[5].name, "query") + async def test_span_name_async(self): + PsycopgInstrumentor().instrument() + + cnx = psycopg.AsyncConnection.connect(database="test") + async with cnx.cursor() as cursor: + await cursor.execute("Test query", ("param1Value", False)) + await cursor.execute( + """multi + line + query""" + ) + await cursor.execute("tab\tseparated query") + await cursor.execute("/* leading comment */ query") + await cursor.execute( + "/* leading comment */ query /* trailing comment */" + ) + await cursor.execute("query /* trailing comment */") + + spans_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans_list), 6) + self.assertEqual(spans_list[0].name, "Test") + self.assertEqual(spans_list[1].name, "multi") + self.assertEqual(spans_list[2].name, "tab") + self.assertEqual(spans_list[3].name, "query") + self.assertEqual(spans_list[4].name, "query") + self.assertEqual(spans_list[5].name, "query") + # pylint: disable=unused-argument def test_not_recording(self): mock_tracer = mock.Mock() @@ -160,6 +348,26 @@ def test_not_recording(self): PsycopgInstrumentor().uninstrument() + # pylint: disable=unused-argument + async def test_not_recording_async(self): + mock_tracer = mock.Mock() + mock_span = mock.Mock() + mock_span.is_recording.return_value = False + mock_tracer.start_span.return_value = mock_span + PsycopgInstrumentor().instrument() + with mock.patch("opentelemetry.trace.get_tracer") as tracer: + tracer.return_value = mock_tracer + cnx = psycopg.AsyncConnection.connect(database="test") + async with cnx.cursor() as cursor: + query = "SELECT * FROM test" + cursor.execute(query) + self.assertFalse(mock_span.is_recording()) + self.assertTrue(mock_span.is_recording.called) + self.assertFalse(mock_span.set_attribute.called) + self.assertFalse(mock_span.set_status.called) + + PsycopgInstrumentor().uninstrument() + # pylint: disable=unused-argument def test_custom_tracer_provider(self): resource = resources.Resource.create({}) diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE b/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/pyproject.toml b/instrumentation/opentelemetry-instrumentation-psycopg2/pyproject.toml index a300fa9fdd..399d5dc466 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/pyproject.toml @@ -25,18 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "psycopg2 >= 2.7.3.1", ] -test = [ - "opentelemetry-instrumentation-psycopg2[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] psycopg2 = "opentelemetry.instrumentation.psycopg2:Psycopg2Instrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/version.py b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/version.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt new file mode 100644 index 0000000000..ade3b5fd26 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +psycopg2==2.9.9 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-psycopg2 diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE b/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pymemcache/pyproject.toml index e37f566b0b..f7f3bc1905 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py index 512ce9ea56..d763734aca 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py @@ -162,14 +162,14 @@ def _get_address_attributes(instance): host, port = instance.server address_attributes[SpanAttributes.NET_PEER_NAME] = host address_attributes[SpanAttributes.NET_PEER_PORT] = port - address_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + address_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) elif isinstance(instance.server, str): address_attributes[SpanAttributes.NET_PEER_NAME] = instance.server - address_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + address_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) return address_attributes diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/version.py b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/version.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py index 35b672bac0..4e29091217 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py @@ -24,15 +24,14 @@ MemcacheUnknownError, ) -# pylint: disable=import-error,no-name-in-module -from tests.utils import MockSocket, _str - from opentelemetry import trace as trace_api from opentelemetry.instrumentation.pymemcache import PymemcacheInstrumentor from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer +from .utils import MockSocket, _str + TEST_HOST = "localhost" TEST_PORT = 117711 diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE b/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pymongo/pyproject.toml index 6df765bfe0..7c1c8a03a5 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-pymongo/pyproject.toml @@ -25,18 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "pymongo >= 3.1, < 5.0", ] -test = [ - "opentelemetry-instrumentation-pymongo[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] pymongo = "opentelemetry.instrumentation.pymongo:PymongoInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py index 506669a5c6..f55aa2be33 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py @@ -98,8 +98,7 @@ def failed_hook(span, event): FailedHookT = Callable[[Span, monitoring.CommandFailedEvent], None] -def dummy_callback(span, event): - ... +def dummy_callback(span, event): ... class CommandTracer(monitoring.CommandListener): diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/version.py b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/version.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt new file mode 100644 index 0000000000..01d48e8dc4 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +dnspython==2.6.1 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pymongo==4.6.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-pymongo diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE b/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pymysql/pyproject.toml index 4018d29601..858fea62fa 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-pymysql/pyproject.toml @@ -25,18 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "PyMySQL < 2", ] -test = [ - "opentelemetry-instrumentation-pymysql[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] pymysql = "opentelemetry.instrumentation.pymysql:PyMySQLInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/version.py b/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/version.py +++ b/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry/instrumentation/pymysql/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt new file mode 100644 index 0000000000..cb6619c5de --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +PyMySQL==1.1.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-pymysql diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE b/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pyramid/pyproject.toml index 4f6577d4a8..49a61287f6 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-pyramid/pyproject.toml @@ -25,10 +25,10 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-wsgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-wsgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py index 4f17da3da5..ede3e09608 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -106,9 +106,9 @@ def _before_traversal(event): if span.is_recording(): attributes = otel_wsgi.collect_request_attributes(request_environ) if request.matched_route: - attributes[ - SpanAttributes.HTTP_ROUTE - ] = request.matched_route.pattern + attributes[SpanAttributes.HTTP_ROUTE] = ( + request.matched_route.pattern + ) for key, value in attributes.items(): span.set_attribute(key, value) if span.kind == trace.SpanKind.SERVER: @@ -201,9 +201,9 @@ def trace_tween(request): status = getattr(response, "status", status) status_code = otel_wsgi._parse_status_code(status) if status_code is not None: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = otel_wsgi._parse_status_code(status) + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + otel_wsgi._parse_status_code(status) + ) duration_histogram.record(duration, duration_attrs) active_requests_counter.add(-1, active_requests_count_attrs) span = request.environ.get(_ENVIRON_SPAN_KEY) diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/version.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/version.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py index 2c3ec85e18..4715e0b461 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py @@ -18,6 +18,10 @@ from pyramid.config import Configurator from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.pyramid import PyramidInstrumentor from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, @@ -31,8 +35,6 @@ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, - _active_requests_count_attrs, - _duration_attrs, ) # pylint: disable=import-error @@ -43,8 +45,8 @@ "http.server.duration", ] _recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, } @@ -213,6 +215,7 @@ def test_basic_metric_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 200, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "GET", @@ -220,6 +223,8 @@ def test_basic_metric_success(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, } metrics_list = self.memory_metrics_reader.get_metrics_data() for metric in ( diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py index 478eab1937..c566c301d8 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py @@ -37,6 +37,7 @@ def expected_attributes(override_attributes): SpanAttributes.HTTP_SERVER_NAME: "localhost", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, + SpanAttributes.NET_HOST_NAME: "localhost", SpanAttributes.HTTP_HOST: "localhost", SpanAttributes.HTTP_TARGET: "/", SpanAttributes.HTTP_FLAVOR: "1.1", diff --git a/instrumentation/opentelemetry-instrumentation-redis/LICENSE b/instrumentation/opentelemetry-instrumentation-redis/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-redis/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-redis/pyproject.toml b/instrumentation/opentelemetry-instrumentation-redis/pyproject.toml index 8511671ed6..76b049b7c8 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-redis/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "wrapt >= 1.12.1", ] @@ -34,11 +34,6 @@ dependencies = [ instruments = [ "redis >= 2.6", ] -test = [ - "opentelemetry-instrumentation-redis[instruments]", - "opentelemetry-sdk ~= 1.3", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] redis = "opentelemetry.instrumentation.redis:RedisInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py index 3c274c8c43..2a24ead79a 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py @@ -36,14 +36,14 @@ def _extract_conn_attributes(conn_kwargs): attributes[SpanAttributes.NET_PEER_PORT] = conn_kwargs.get( "port", 6379 ) - attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) except KeyError: attributes[SpanAttributes.NET_PEER_NAME] = conn_kwargs.get("path", "") - attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) return attributes diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/version.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/version.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt new file mode 100644 index 0000000000..90617f72e6 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +async-timeout==4.0.3 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +redis==5.0.1 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-redis diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE b/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/pyproject.toml b/instrumentation/opentelemetry-instrumentation-remoulade/pyproject.toml index b8c9d2709b..ba23cc0b0a 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-remoulade/pyproject.toml @@ -25,19 +25,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "remoulade >= 0.50", ] -test = [ - "opentelemetry-instrumentation-remoulade[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "opentelemetry-sdk ~= 1.10" -] [project.entry-points.opentelemetry_instrumentor] remoulade = "opentelemetry.instrumentation.remoulade:RemouladeInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt similarity index 66% rename from instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt rename to instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt index 4bd1d0d318..c50dfde9b5 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt +++ b/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt @@ -1,22 +1,22 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -elasticsearch==6.8.2 -elasticsearch-dsl==6.4.0 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 pluggy==1.4.0 +prometheus_client==0.20.0 py==1.11.0 py-cpuinfo==9.0.0 pytest==7.1.3 pytest-benchmark==4.0.0 python-dateutil==2.8.2 +pytz==2024.1 +remoulade==3.2.0 six==1.16.0 tomli==2.0.1 -typing_extensions==4.10.0 -urllib3==2.2.1 +typing_extensions==4.9.0 wrapt==1.16.0 zipp==3.17.0 -e opentelemetry-instrumentation --e instrumentation/opentelemetry-instrumentation-elasticsearch +-e instrumentation/opentelemetry-instrumentation-remoulade diff --git a/instrumentation/opentelemetry-instrumentation-requests/LICENSE b/instrumentation/opentelemetry-instrumentation-requests/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-requests/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml b/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml index ce83ca93ac..6252ab3de9 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index d0150d57b7..12797d6f5e 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -63,18 +63,20 @@ _SPAN_ATTRIBUTES_ERROR_TYPE, _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS, _SPAN_ATTRIBUTES_NETWORK_PEER_PORT, - _filter_duration_attrs, + _client_duration_attrs_new, + _client_duration_attrs_old, + _filter_semconv_duration_attrs, _get_schema_url, + _HTTPStabilityMode, _OpenTelemetrySemanticConventionStability, - _OpenTelemetryStabilityMode, _OpenTelemetryStabilitySignalType, _report_new, _report_old, - _set_http_hostname, + _set_http_host, _set_http_method, - _set_http_net_peer_name, + _set_http_net_peer_name_client, _set_http_network_protocol_version, - _set_http_port, + _set_http_peer_port_client, _set_http_scheme, _set_http_status_code, _set_http_url, @@ -117,7 +119,7 @@ def _instrument( request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, excluded_urls: ExcludeList = None, - sem_conv_opt_in_mode: _OpenTelemetryStabilityMode = _OpenTelemetryStabilityMode.DEFAULT, + sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, ): """Enables tracing of all requests calls that go through :code:`requests.session.Session.request` (this includes @@ -170,38 +172,40 @@ def get_or_create_headers(): try: parsed_url = urlparse(url) if parsed_url.scheme: - _set_http_scheme( - metric_labels, parsed_url.scheme, sem_conv_opt_in_mode - ) + if _report_old(sem_conv_opt_in_mode): + # TODO: Support opt-in for url.scheme in new semconv + _set_http_scheme( + metric_labels, parsed_url.scheme, sem_conv_opt_in_mode + ) if parsed_url.hostname: - _set_http_hostname( + _set_http_host( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) - _set_http_net_peer_name( + _set_http_net_peer_name_client( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) if _report_new(sem_conv_opt_in_mode): - _set_http_hostname( + _set_http_host( span_attributes, parsed_url.hostname, sem_conv_opt_in_mode, ) # Use semconv library when available - span_attributes[ - _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS - ] = parsed_url.hostname + span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS] = ( + parsed_url.hostname + ) if parsed_url.port: - _set_http_port( + _set_http_peer_port_client( metric_labels, parsed_url.port, sem_conv_opt_in_mode ) if _report_new(sem_conv_opt_in_mode): - _set_http_port( + _set_http_peer_port_client( span_attributes, parsed_url.port, sem_conv_opt_in_mode ) # Use semconv library when available - span_attributes[ - _SPAN_ATTRIBUTES_NETWORK_PEER_PORT - ] = parsed_url.port + span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_PORT] = ( + parsed_url.port + ) except ValueError: pass @@ -284,16 +288,22 @@ def get_or_create_headers(): ).__qualname__ if duration_histogram_old is not None: - duration_attrs_old = _filter_duration_attrs( - metric_labels, _OpenTelemetryStabilityMode.DEFAULT + duration_attrs_old = _filter_semconv_duration_attrs( + metric_labels, + _client_duration_attrs_old, + _client_duration_attrs_new, + _HTTPStabilityMode.DEFAULT, ) duration_histogram_old.record( max(round(elapsed_time * 1000), 0), attributes=duration_attrs_old, ) if duration_histogram_new is not None: - duration_attrs_new = _filter_duration_attrs( - metric_labels, _OpenTelemetryStabilityMode.HTTP + duration_attrs_new = _filter_semconv_duration_attrs( + metric_labels, + _client_duration_attrs_old, + _client_duration_attrs_new, + _HTTPStabilityMode.HTTP, ) duration_histogram_new.record( elapsed_time, attributes=duration_attrs_new @@ -341,7 +351,10 @@ def get_default_span_name(method): Returns: span name """ - return sanitize_method(method.upper().strip()) + method = sanitize_method(method.upper().strip()) + if method == "_OTHER": + return "HTTP" + return method class RequestsInstrumentor(BaseInstrumentor): @@ -402,9 +415,11 @@ def _instrument(self, **kwargs): duration_histogram_new, request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), sem_conv_opt_in_mode=semconv_opt_in_mode, ) diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py index 8424bfeb2a..9cd93a9150 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py @@ -16,3 +16,5 @@ _instruments = ("requests ~= 2.0",) _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/version.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/version.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py index 8817053068..d85d70e20e 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py +++ b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py @@ -23,10 +23,10 @@ import opentelemetry.instrumentation.requests from opentelemetry import trace from opentelemetry.instrumentation._semconv import ( - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY, _SPAN_ATTRIBUTES_ERROR_TYPE, _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS, _SPAN_ATTRIBUTES_NETWORK_PEER_PORT, + OTEL_SEMCONV_STABILITY_OPT_IN, _OpenTelemetrySemanticConventionStability, ) from opentelemetry.instrumentation.requests import RequestsInstrumentor @@ -88,7 +88,7 @@ def setUp(self): "os.environ", { "OTEL_PYTHON_REQUESTS_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg", - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY: sem_conv_mode, + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) @@ -524,7 +524,6 @@ def test_requests_exception_new_semconv(self, *_, **__): self.perform_request(url_with_port) span = self.assert_span() - print(span.attributes) self.assertEqual( span.attributes, { @@ -671,7 +670,7 @@ def setUp(self): self.env_patch = mock.patch.dict( "os.environ", { - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY: sem_conv_mode, + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) self.env_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE b/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/pyproject.toml b/instrumentation/opentelemetry-instrumentation-sklearn/pyproject.toml index 28fa247159..ebda48982a 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-sklearn/pyproject.toml @@ -25,17 +25,13 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", ] [project.optional-dependencies] instruments = [ "scikit-learn ~= 0.24.0", ] -test = [ - "opentelemetry-instrumentation-sklearn[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] sklearn = "opentelemetry.instrumentation.sklearn:SklearnInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry/instrumentation/sklearn/version.py b/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry/instrumentation/sklearn/version.py index f7a124c7b8..604195c10e 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry/instrumentation/sklearn/version.py +++ b/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry/instrumentation/sklearn/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt new file mode 100644 index 0000000000..fc966b4d6a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +joblib==1.3.2 +numpy==1.24.4 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +scikit-learn==0.24.2 +scipy==1.10.1 +threadpoolctl==3.3.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-sklearn diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE b/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/pyproject.toml b/instrumentation/opentelemetry-instrumentation-sqlalchemy/pyproject.toml index bf5759e57b..338606aa6e 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", "packaging >= 21.0", "wrapt >= 1.11.2", ] diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index 0632d71faf..172c1193f3 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -15,13 +15,13 @@ import re import weakref +import sqlalchemy from sqlalchemy.event import ( # pylint: disable=no-name-in-module listen, remove, ) from opentelemetry import trace -from opentelemetry.instrumentation.sqlalchemy.version import __version__ from opentelemetry.instrumentation.sqlcommenter_utils import _add_sql_comment from opentelemetry.instrumentation.utils import _get_opentelemetry_values from opentelemetry.semconv.trace import NetTransportValues, SpanAttributes @@ -227,7 +227,7 @@ def _before_cur_exec( commenter_data = { "db_driver": conn.engine.driver, # Driver/framework centric information. - "db_framework": f"sqlalchemy:{__version__}", + "db_framework": f"sqlalchemy:{sqlalchemy.__version__}", } if self.commenter_options.get("opentelemetry_values", True): @@ -296,18 +296,18 @@ def _get_attributes_from_cursor(vendor, cursor, attrs): is_unix_socket = info.host and info.host.startswith("/") if is_unix_socket: - attrs[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + attrs[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) if info.port: # postgresql enforces this pattern on all socket names attrs[SpanAttributes.NET_PEER_NAME] = os.path.join( info.host, f".s.PGSQL.{info.port}" ) else: - attrs[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + attrs[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) attrs[SpanAttributes.NET_PEER_NAME] = info.host if info.port: attrs[SpanAttributes.NET_PEER_PORT] = int(info.port) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/version.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/version.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE b/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/pyproject.toml b/instrumentation/opentelemetry-instrumentation-sqlite3/pyproject.toml index 0ccdc2da06..05bda3d1d0 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/pyproject.toml @@ -25,15 +25,12 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-dbapi == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-dbapi == 0.46b0.dev", ] [project.optional-dependencies] instruments = [] -test = [ - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] sqlite3 = "opentelemetry.instrumentation.sqlite3:SQLite3Instrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/version.py b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/version.py index 6340c1adfb..17627b21dc 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/version.py +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/version.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt new file mode 100644 index 0000000000..16cfb33801 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-dbapi +-e instrumentation/opentelemetry-instrumentation-sqlite3 diff --git a/instrumentation/opentelemetry-instrumentation-starlette/LICENSE b/instrumentation/opentelemetry-instrumentation-starlette/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-starlette/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml b/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml index a73d5b0455..69805b660c 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml @@ -25,10 +25,10 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-instrumentation-asgi == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-instrumentation-asgi == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/version.py b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/version.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/pyproject.toml b/instrumentation/opentelemetry-instrumentation-system-metrics/pyproject.toml index caf27ec5ab..fe60ca1251 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-api ~= 1.11", "opentelemetry-sdk ~= 1.11", "psutil ~= 5.9", @@ -33,10 +34,6 @@ dependencies = [ instruments = [ "psutil >= 5", ] -test = [ - "opentelemetry-instrumentation-system-metrics[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] system_metrics = "opentelemetry.instrumentation.system_metrics:SystemMetricsInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 32766fa0c5..74d4f6a431 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -481,9 +481,11 @@ def _get_system_swap_utilization( if hasattr(system_swap, metric): self._system_swap_utilization_labels["state"] = metric yield Observation( - getattr(system_swap, metric) / system_swap.total - if system_swap.total - else 0, + ( + getattr(system_swap, metric) / system_swap.total + if system_swap.total + else 0 + ), self._system_swap_utilization_labels.copy(), ) @@ -556,9 +558,9 @@ def _get_system_network_dropped_packets( for metric in self._config["system.network.dropped.packets"]: in_out = {"receive": "in", "transmit": "out"}[metric] if hasattr(counters, f"drop{in_out}"): - self._system_network_dropped_packets_labels[ - "device" - ] = device + self._system_network_dropped_packets_labels["device"] = ( + device + ) self._system_network_dropped_packets_labels[ "direction" ] = metric @@ -629,9 +631,9 @@ def _get_system_network_connections( 1: "tcp", 2: "udp", }[net_connection.type.value] - self._system_network_connections_labels[ - "state" - ] = net_connection.status + self._system_network_connections_labels["state"] = ( + net_connection.status + ) self._system_network_connections_labels[metric] = getattr( net_connection, metric ) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/version.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/version.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt new file mode 100644 index 0000000000..ee56025d5f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +psutil==5.9.8 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-system-metrics diff --git a/instrumentation/opentelemetry-instrumentation-threading/LICENSE b/instrumentation/opentelemetry-instrumentation-threading/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/LICENSE @@ -0,0 +1,201 @@ + 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. diff --git a/instrumentation/opentelemetry-instrumentation-threading/README.rst b/instrumentation/opentelemetry-instrumentation-threading/README.rst new file mode 100644 index 0000000000..93097dfcb6 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/README.rst @@ -0,0 +1,25 @@ +OpenTelemetry threading Instrumentation +======================================= + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-threading.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-threading/ + +This library provides instrumentation for the `threading` module to ensure that +the OpenTelemetry context is propagated across threads. It is important to note +that this instrumentation does not produce any telemetry data on its own. It +merely ensures that the context is correctly propagated when threads are used. + +Installation +------------ + +:: + + pip install opentelemetry-instrumentation-threading + +References +---------- + +* `OpenTelemetry Threading Tracing `_ +* `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-threading/pyproject.toml b/instrumentation/opentelemetry-instrumentation-threading/pyproject.toml new file mode 100644 index 0000000000..16874b13f9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/pyproject.toml @@ -0,0 +1,51 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-instrumentation-threading" +dynamic = ["version"] +description = "Thread context propagation support for OpenTelemetry" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.8" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "opentelemetry-api ~= 1.12", + "opentelemetry-instrumentation == 0.46b0.dev", + "wrapt >= 1.0.0, < 2.0.0", +] + +[project.optional-dependencies] +instruments = [] + +[project.entry-points.opentelemetry_instrumentor] +threading = "opentelemetry.instrumentation.threading:ThreadingInstrumentor" + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-threading" + +[tool.hatch.version] +path = "src/opentelemetry/instrumentation/threading/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py new file mode 100644 index 0000000000..be1eec139e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/__init__.py @@ -0,0 +1,149 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Instrument threading to propagate OpenTelemetry context. + +Usage +----- + +.. code-block:: python + + from opentelemetry.instrumentation.threading import ThreadingInstrumentor + + ThreadingInstrumentor().instrument() + +This library provides instrumentation for the `threading` module to ensure that +the OpenTelemetry context is propagated across threads. It is important to note +that this instrumentation does not produce any telemetry data on its own. It +merely ensures that the context is correctly propagated when threads are used. + + +When instrumented, new threads created using threading.Thread, threading.Timer, +or within futures.ThreadPoolExecutor will have the current OpenTelemetry +context attached, and this context will be re-activated in the thread's +run method or the executor's worker thread." +""" + +import threading +from concurrent import futures +from typing import Collection + +from wrapt import wrap_function_wrapper + +from opentelemetry import context +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.threading.package import _instruments +from opentelemetry.instrumentation.utils import unwrap + + +class ThreadingInstrumentor(BaseInstrumentor): + __WRAPPER_START_METHOD = "start" + __WRAPPER_RUN_METHOD = "run" + __WRAPPER_SUBMIT_METHOD = "submit" + + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + + def _instrument(self, **kwargs): + self._instrument_thread() + self._instrument_timer() + self._instrument_thread_pool() + + def _uninstrument(self, **kwargs): + self._uninstrument_thread() + self._uninstrument_timer() + self._uninstrument_thread_pool() + + @staticmethod + def _instrument_thread(): + wrap_function_wrapper( + threading.Thread, + ThreadingInstrumentor.__WRAPPER_START_METHOD, + ThreadingInstrumentor.__wrap_threading_start, + ) + wrap_function_wrapper( + threading.Thread, + ThreadingInstrumentor.__WRAPPER_RUN_METHOD, + ThreadingInstrumentor.__wrap_threading_run, + ) + + @staticmethod + def _instrument_timer(): + wrap_function_wrapper( + threading.Timer, + ThreadingInstrumentor.__WRAPPER_START_METHOD, + ThreadingInstrumentor.__wrap_threading_start, + ) + wrap_function_wrapper( + threading.Timer, + ThreadingInstrumentor.__WRAPPER_RUN_METHOD, + ThreadingInstrumentor.__wrap_threading_run, + ) + + @staticmethod + def _instrument_thread_pool(): + wrap_function_wrapper( + futures.ThreadPoolExecutor, + ThreadingInstrumentor.__WRAPPER_SUBMIT_METHOD, + ThreadingInstrumentor.__wrap_thread_pool_submit, + ) + + @staticmethod + def _uninstrument_thread(): + unwrap(threading.Thread, ThreadingInstrumentor.__WRAPPER_START_METHOD) + unwrap(threading.Thread, ThreadingInstrumentor.__WRAPPER_RUN_METHOD) + + @staticmethod + def _uninstrument_timer(): + unwrap(threading.Timer, ThreadingInstrumentor.__WRAPPER_START_METHOD) + unwrap(threading.Timer, ThreadingInstrumentor.__WRAPPER_RUN_METHOD) + + @staticmethod + def _uninstrument_thread_pool(): + unwrap( + futures.ThreadPoolExecutor, + ThreadingInstrumentor.__WRAPPER_SUBMIT_METHOD, + ) + + @staticmethod + def __wrap_threading_start(call_wrapped, instance, args, kwargs): + instance._otel_context = context.get_current() + return call_wrapped(*args, **kwargs) + + @staticmethod + def __wrap_threading_run(call_wrapped, instance, args, kwargs): + token = None + try: + token = context.attach(instance._otel_context) + return call_wrapped(*args, **kwargs) + finally: + context.detach(token) + + @staticmethod + def __wrap_thread_pool_submit(call_wrapped, instance, args, kwargs): + # obtain the original function and wrapped kwargs + original_func = args[0] + otel_context = context.get_current() + + def wrapped_func(*func_args, **func_kwargs): + token = None + try: + token = context.attach(otel_context) + return original_func(*func_args, **func_kwargs) + finally: + context.detach(token) + + # replace the original function with the wrapped function + new_args = (wrapped_func,) + args[1:] + return call_wrapped(*new_args, **kwargs) diff --git a/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/package.py b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/package.py new file mode 100644 index 0000000000..1bf177779b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/package.py @@ -0,0 +1,17 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +_instruments = () + +_supports_metrics = False diff --git a/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/version.py b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/version.py new file mode 100644 index 0000000000..ff4933b20b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry/instrumentation/threading/version.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt new file mode 100644 index 0000000000..ffda21f234 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt @@ -0,0 +1,18 @@ +asgiref==3.7.2 +attrs==23.2.0 +confluent-kafka==2.3.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-threading diff --git a/instrumentation/opentelemetry-instrumentation-threading/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-threading/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/instrumentation/opentelemetry-instrumentation-threading/tests/test_threading.py b/instrumentation/opentelemetry-instrumentation-threading/tests/test_threading.py new file mode 100644 index 0000000000..15f67b8d61 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-threading/tests/test_threading.py @@ -0,0 +1,226 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import threading +from concurrent.futures import ThreadPoolExecutor +from typing import List + +from opentelemetry import trace +from opentelemetry.instrumentation.threading import ThreadingInstrumentor +from opentelemetry.test.test_base import TestBase + + +class TestThreading(TestBase): + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + self._mock_span_contexts: List[trace.SpanContext] = [] + ThreadingInstrumentor().instrument() + + def tearDown(self): + ThreadingInstrumentor().uninstrument() + super().tearDown() + + def get_root_span(self): + return self._tracer.start_as_current_span("rootSpan") + + def test_trace_context_propagation_in_thread(self): + self.run_threading_test(threading.Thread(target=self.fake_func)) + + def test_trace_context_propagation_in_timer(self): + self.run_threading_test( + threading.Timer(interval=1, function=self.fake_func) + ) + + def run_threading_test(self, thread: threading.Thread): + with self.get_root_span() as span: + expected_span_context = span.get_span_context() + thread.start() + thread.join() + + # check result + self.assertEqual(len(self._mock_span_contexts), 1) + self.assertEqual( + self._mock_span_contexts[0], expected_span_context + ) + + def test_trace_context_propagation_in_thread_pool_with_multiple_workers( + self, + ): + max_workers = 10 + executor = ThreadPoolExecutor(max_workers=max_workers) + + expected_span_contexts: List[trace.SpanContext] = [] + futures_list = [] + for num in range(max_workers): + with self._tracer.start_as_current_span(f"trace_{num}") as span: + expected_span_context = span.get_span_context() + expected_span_contexts.append(expected_span_context) + future = executor.submit( + self.get_current_span_context_for_test + ) + futures_list.append(future) + + result_span_contexts = [future.result() for future in futures_list] + + # check result + self.assertEqual(result_span_contexts, expected_span_contexts) + + def test_trace_context_propagation_in_thread_pool_with_single_worker(self): + max_workers = 1 + with ThreadPoolExecutor(max_workers=max_workers) as executor: + # test propagation of the same trace context across multiple tasks + with self._tracer.start_as_current_span("task") as task_span: + expected_task_context = task_span.get_span_context() + future1 = executor.submit( + self.get_current_span_context_for_test + ) + future2 = executor.submit( + self.get_current_span_context_for_test + ) + + # check result + self.assertEqual(future1.result(), expected_task_context) + self.assertEqual(future2.result(), expected_task_context) + + # test propagation of different trace contexts across tasks in sequence + with self._tracer.start_as_current_span("task1") as task1_span: + expected_task1_context = task1_span.get_span_context() + future1 = executor.submit( + self.get_current_span_context_for_test + ) + + # check result + self.assertEqual(future1.result(), expected_task1_context) + + with self._tracer.start_as_current_span("task2") as task2_span: + expected_task2_context = task2_span.get_span_context() + future2 = executor.submit( + self.get_current_span_context_for_test + ) + + # check result + self.assertEqual(future2.result(), expected_task2_context) + + def fake_func(self): + span_context = self.get_current_span_context_for_test() + self._mock_span_contexts.append(span_context) + + @staticmethod + def get_current_span_context_for_test() -> trace.SpanContext: + return trace.get_current_span().get_span_context() + + def print_square(self, num): + with self._tracer.start_as_current_span("square"): + return num * num + + def print_cube(self, num): + with self._tracer.start_as_current_span("cube"): + return num * num * num + + def print_square_with_thread(self, num): + with self._tracer.start_as_current_span("square"): + cube_thread = threading.Thread(target=self.print_cube, args=(10,)) + + cube_thread.start() + cube_thread.join() + return num * num + + def calculate(self, num): + with self._tracer.start_as_current_span("calculate"): + square_thread = threading.Thread( + target=self.print_square, args=(num,) + ) + cube_thread = threading.Thread(target=self.print_cube, args=(num,)) + square_thread.start() + square_thread.join() + + cube_thread.start() + cube_thread.join() + + def test_without_thread_nesting(self): + square_thread = threading.Thread(target=self.print_square, args=(10,)) + + with self._tracer.start_as_current_span("root"): + square_thread.start() + square_thread.join() + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 2) + + # pylint: disable=unbalanced-tuple-unpacking + target, root = spans[:2] + + self.assertIs(target.parent, root.get_span_context()) + self.assertIsNone(root.parent) + + def test_with_thread_nesting(self): + # + # Following scenario is tested. + # threadA -> methodA -> threadB -> methodB + # + + square_thread = threading.Thread( + target=self.print_square_with_thread, args=(10,) + ) + + with self._tracer.start_as_current_span("root"): + square_thread.start() + square_thread.join() + + spans = self.memory_exporter.get_finished_spans() + + self.assertEqual(len(spans), 3) + # pylint: disable=unbalanced-tuple-unpacking + cube, square, root = spans[:3] + + self.assertIs(cube.parent, square.get_span_context()) + self.assertIs(square.parent, root.get_span_context()) + self.assertIsNone(root.parent) + + def test_with_thread_multi_nesting(self): + # + # Following scenario is tested. + # / threadB -> methodB + # threadA -> methodA -> + # \ threadC -> methodC + # + calculate_thread = threading.Thread(target=self.calculate, args=(10,)) + + with self._tracer.start_as_current_span("root"): + calculate_thread.start() + calculate_thread.join() + + spans = self.memory_exporter.get_finished_spans() + + self.assertEqual(len(spans), 4) + + # pylint: disable=unbalanced-tuple-unpacking + cube, square, calculate, root = spans[:4] + + self.assertIs(cube.parent, calculate.get_span_context()) + self.assertIs(square.parent, calculate.get_span_context()) + self.assertIs(calculate.parent, root.get_span_context()) + self.assertIsNone(root.parent) + + def test_uninstrumented(self): + ThreadingInstrumentor().uninstrument() + + square_thread = threading.Thread(target=self.print_square, args=(10,)) + square_thread.start() + square_thread.join() + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + ThreadingInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-tornado/LICENSE b/instrumentation/opentelemetry-instrumentation-tornado/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-tornado/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml b/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml index e56a566410..ea1c48f011 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml @@ -24,9 +24,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index 5a39538837..5c99457a39 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -455,9 +455,9 @@ def _get_attributes_from_request(request): if hasattr(request.connection, "context") and getattr( request.connection.context, "_orig_remote_ip", None ): - attrs[ - SpanAttributes.NET_PEER_IP - ] = request.connection.context._orig_remote_ip + attrs[SpanAttributes.NET_PEER_IP] = ( + request.connection.context._orig_remote_ip + ) return extract_attributes_from_object( request, _traced_request_attrs, attrs diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/version.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/version.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE b/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/pyproject.toml b/instrumentation/opentelemetry-instrumentation-tortoiseorm/pyproject.toml index 9d32028bdd..62e5da5b54 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", ] [project.optional-dependencies] @@ -34,10 +34,6 @@ instruments = [ "tortoise-orm >= 0.17.0", "pydantic >= 1.10.2" ] -test = [ - "opentelemetry-instrumentation-tortoiseorm[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] tortoiseorm = "opentelemetry.instrumentation.tortoiseorm:TortoiseORMInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py index 7988daf130..cebcb81ced 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py @@ -229,17 +229,17 @@ def _hydrate_span_from_args(self, connection, query, parameters) -> dict: capabilities = getattr(connection, "capabilities", None) if capabilities is not None: if capabilities.dialect == "sqlite": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.SQLITE.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.SQLITE.value + ) elif capabilities.dialect == "postgres": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.POSTGRESQL.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.POSTGRESQL.value + ) elif capabilities.dialect == "mysql": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.MYSQL.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.MYSQL.value + ) dbname = getattr(connection, "filename", None) if dbname: span_attributes[SpanAttributes.DB_NAME] = dbname diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/version.py b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/version.py +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt new file mode 100644 index 0000000000..0fafc56253 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt @@ -0,0 +1,25 @@ +aiosqlite==0.17.0 +annotated-types==0.6.0 +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +iso8601==1.1.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pydantic==2.6.2 +pydantic_core==2.16.3 +pypika-tortoise==0.1.6 +pytest==7.1.3 +pytest-benchmark==4.0.0 +pytz==2024.1 +tomli==2.0.1 +tortoise-orm==0.20.0 +typing_extensions==4.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-tortoiseorm diff --git a/instrumentation/opentelemetry-instrumentation-urllib/LICENSE b/instrumentation/opentelemetry-instrumentation-urllib/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-urllib/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml b/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml index 08a0f90aca..1011912a53 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py index 3738c4d2c6..befc022b35 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -156,9 +156,11 @@ def _instrument(self, **kwargs): histograms, request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), ) def _uninstrument(self, **kwargs): @@ -251,9 +253,9 @@ def _instrumented_open_call( ver_ = str(getattr(result, "version", "")) if ver_: - labels[ - SpanAttributes.HTTP_FLAVOR - ] = f"{ver_[:1]}.{ver_[:-1]}" + labels[SpanAttributes.HTTP_FLAVOR] = ( + f"{ver_[:1]}.{ver_[:-1]}" + ) _record_histograms( histograms, labels, request, result, elapsed_time diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py index 6340c1adfb..17627b21dc 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/version.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE b/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml b/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml index 628cb46554..b5fafc0fe9 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index 985f291199..add5db8f19 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -200,9 +200,11 @@ def _instrument(self, **kwargs): request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), url_filter=kwargs.get("url_filter"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), ) def _uninstrument(self, **kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/version.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/version.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE b/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml index 69b0e7ff41..e3e8bca651 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-util-http == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", + "opentelemetry-semantic-conventions == 0.46b0.dev", + "opentelemetry-util-http == 0.46b0.dev", ] [project.optional-dependencies] diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index 1568271703..19065f7bcc 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -215,10 +215,34 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he from typing import DefaultDict from opentelemetry import context, trace -from opentelemetry.instrumentation.utils import ( - _start_internal_or_server_span, - http_status_to_status_code, +from opentelemetry.instrumentation._semconv import ( + _METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + _SPAN_ATTRIBUTES_ERROR_TYPE, + _filter_semconv_active_request_count_attr, + _filter_semconv_duration_attrs, + _get_schema_url, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _OpenTelemetryStabilitySignalType, + _report_new, + _report_old, + _server_active_requests_count_attrs_new, + _server_active_requests_count_attrs_old, + _server_duration_attrs_new, + _server_duration_attrs_old, + _set_http_flavor_version, + _set_http_method, + _set_http_net_host, + _set_http_net_host_port, + _set_http_net_peer_name_server, + _set_http_peer_ip, + _set_http_peer_port_server, + _set_http_scheme, + _set_http_target, + _set_http_user_agent, + _set_status, ) +from opentelemetry.instrumentation.utils import _start_internal_or_server_span from opentelemetry.instrumentation.wsgi.version import __version__ from opentelemetry.metrics import get_meter from opentelemetry.propagators.textmap import Getter @@ -230,6 +254,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, SanitizeValue, + _parse_url_query, get_custom_headers, normalise_request_header_name, normalise_response_header_name, @@ -241,26 +266,6 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he _CARRIER_KEY_PREFIX = "HTTP_" _CARRIER_KEY_PREFIX_LEN = len(_CARRIER_KEY_PREFIX) -# List of recommended attributes -_duration_attrs = [ - SpanAttributes.HTTP_METHOD, - SpanAttributes.HTTP_HOST, - SpanAttributes.HTTP_SCHEME, - SpanAttributes.HTTP_STATUS_CODE, - SpanAttributes.HTTP_FLAVOR, - SpanAttributes.HTTP_SERVER_NAME, - SpanAttributes.NET_HOST_NAME, - SpanAttributes.NET_HOST_PORT, -] - -_active_requests_count_attrs = [ - SpanAttributes.HTTP_METHOD, - SpanAttributes.HTTP_HOST, - SpanAttributes.HTTP_SCHEME, - SpanAttributes.HTTP_FLAVOR, - SpanAttributes.HTTP_SERVER_NAME, -] - class WSGIGetter(Getter[dict]): def get( @@ -298,53 +303,84 @@ def setifnotnone(dic, key, value): dic[key] = value -def collect_request_attributes(environ): +# pylint: disable=too-many-branches + + +def collect_request_attributes( + environ, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): """Collects HTTP request attributes from the PEP3333-conforming WSGI environ and returns a dictionary to be used as span creation attributes. """ + result = {} + _set_http_method( + result, + environ.get("REQUEST_METHOD", ""), + sanitize_method(environ.get("REQUEST_METHOD", "")), + sem_conv_opt_in_mode, + ) + # old semconv v1.12.0 + server_name = environ.get("SERVER_NAME") + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_SERVER_NAME] = server_name + + _set_http_scheme( + result, + environ.get("wsgi.url_scheme"), + sem_conv_opt_in_mode, + ) - result = { - SpanAttributes.HTTP_METHOD: sanitize_method( - environ.get("REQUEST_METHOD") - ), - SpanAttributes.HTTP_SERVER_NAME: environ.get("SERVER_NAME"), - SpanAttributes.HTTP_SCHEME: environ.get("wsgi.url_scheme"), - } - + host = environ.get("HTTP_HOST") host_port = environ.get("SERVER_PORT") - if host_port is not None and not host_port == "": - result.update({SpanAttributes.NET_HOST_PORT: int(host_port)}) + if host: + _set_http_net_host(result, host, sem_conv_opt_in_mode) + # old semconv v1.12.0 + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_HOST] = host + if host_port: + _set_http_net_host_port( + result, + int(host_port), + sem_conv_opt_in_mode, + ) - setifnotnone(result, SpanAttributes.HTTP_HOST, environ.get("HTTP_HOST")) target = environ.get("RAW_URI") if target is None: # Note: `"" or None is None` target = environ.get("REQUEST_URI") - if target is not None: - result[SpanAttributes.HTTP_TARGET] = target + if target: + path, query = _parse_url_query(target) + _set_http_target(result, target, path, query, sem_conv_opt_in_mode) else: - result[SpanAttributes.HTTP_URL] = remove_url_credentials( - wsgiref_util.request_uri(environ) - ) + # old semconv v1.20.0 + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_URL] = remove_url_credentials( + wsgiref_util.request_uri(environ) + ) remote_addr = environ.get("REMOTE_ADDR") if remote_addr: - result[SpanAttributes.NET_PEER_IP] = remote_addr + _set_http_peer_ip(result, remote_addr, sem_conv_opt_in_mode) + + peer_port = environ.get("REMOTE_PORT") + if peer_port: + _set_http_peer_port_server(result, peer_port, sem_conv_opt_in_mode) + remote_host = environ.get("REMOTE_HOST") if remote_host and remote_host != remote_addr: - result[SpanAttributes.NET_PEER_NAME] = remote_host + _set_http_net_peer_name_server( + result, remote_host, sem_conv_opt_in_mode + ) user_agent = environ.get("HTTP_USER_AGENT") if user_agent is not None and len(user_agent) > 0: - result[SpanAttributes.HTTP_USER_AGENT] = user_agent + _set_http_user_agent(result, user_agent, sem_conv_opt_in_mode) - setifnotnone( - result, SpanAttributes.NET_PEER_PORT, environ.get("REMOTE_PORT") - ) flavor = environ.get("SERVER_PROTOCOL", "") if flavor.upper().startswith(_HTTP_VERSION_PREFIX): flavor = flavor[len(_HTTP_VERSION_PREFIX) :] if flavor: - result[SpanAttributes.HTTP_FLAVOR] = flavor + _set_http_flavor_version(result, flavor, sem_conv_opt_in_mode) return result @@ -408,46 +444,56 @@ def _parse_status_code(resp_status): return None -def _parse_active_request_count_attrs(req_attrs): - active_requests_count_attrs = {} - for attr_key in _active_requests_count_attrs: - if req_attrs.get(attr_key) is not None: - active_requests_count_attrs[attr_key] = req_attrs[attr_key] - return active_requests_count_attrs +def _parse_active_request_count_attrs( + req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT +): + return _filter_semconv_active_request_count_attr( + req_attrs, + _server_active_requests_count_attrs_old, + _server_active_requests_count_attrs_new, + sem_conv_opt_in_mode, + ) -def _parse_duration_attrs(req_attrs): - duration_attrs = {} - for attr_key in _duration_attrs: - if req_attrs.get(attr_key) is not None: - duration_attrs[attr_key] = req_attrs[attr_key] - return duration_attrs +def _parse_duration_attrs( + req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT +): + return _filter_semconv_duration_attrs( + req_attrs, + _server_duration_attrs_old, + _server_duration_attrs_new, + sem_conv_opt_in_mode, + ) def add_response_attributes( - span, start_response_status, response_headers + span, + start_response_status, + response_headers, + duration_attrs=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, ): # pylint: disable=unused-argument """Adds HTTP response attributes to span using the arguments passed to a PEP3333-conforming start_response callable. """ if not span.is_recording(): return - status_code, _ = start_response_status.split(" ", 1) + status_code_str, _ = start_response_status.split(" ", 1) + status_code = 0 try: - status_code = int(status_code) + status_code = int(status_code_str) except ValueError: - span.set_status( - Status( - StatusCode.ERROR, - "Non-integer HTTP status: " + repr(status_code), - ) - ) - else: - span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - span.set_status( - Status(http_status_to_status_code(status_code, server_span=True)) - ) + status_code = -1 + if duration_attrs is None: + duration_attrs = {} + _set_status( + span, + duration_attrs, + status_code_str, + status_code, + sem_conv_opt_in_mode, + ) def get_default_span_name(environ): @@ -462,6 +508,8 @@ def get_default_span_name(environ): The span name. """ method = sanitize_method(environ.get("REQUEST_METHOD", "").strip()) + if method == "_OTHER": + return "HTTP" path = environ.get("PATH_INFO", "").strip() if method and path: return f"{method} {path}" @@ -493,42 +541,66 @@ def __init__( tracer_provider=None, meter_provider=None, ): + # initialize semantic conventions opt-in if needed + _OpenTelemetrySemanticConventionStability._initialize() + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) self.wsgi = wsgi self.tracer = trace.get_tracer( __name__, __version__, tracer_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) self.meter = get_meter( __name__, __version__, meter_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", - ) - self.duration_histogram = self.meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) + self.duration_histogram_old = None + if _report_old(sem_conv_opt_in_mode): + self.duration_histogram_old = self.meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + self.duration_histogram_new = None + if _report_new(sem_conv_opt_in_mode): + self.duration_histogram_new = self.meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) + # We don't need a separate active request counter for old/new semantic conventions + # because the new attributes are a subset of the old attributes self.active_requests_counter = self.meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, - unit="requests", - description="measures the number of concurrent HTTP requests that are currently in-flight", + unit="{request}", + description="Number of active HTTP server requests.", ) self.request_hook = request_hook self.response_hook = response_hook + self._sem_conv_opt_in_mode = sem_conv_opt_in_mode @staticmethod def _create_start_response( - span, start_response, response_hook, duration_attrs + span, + start_response, + response_hook, + duration_attrs, + sem_conv_opt_in_mode, ): @functools.wraps(start_response) def _start_response(status, response_headers, *args, **kwargs): - add_response_attributes(span, status, response_headers) - status_code = _parse_status_code(status) - if status_code is not None: - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = status_code + add_response_attributes( + span, + status, + response_headers, + duration_attrs, + sem_conv_opt_in_mode, + ) if span.is_recording() and span.kind == trace.SpanKind.SERVER: custom_attributes = collect_custom_response_headers_attributes( response_headers @@ -549,11 +621,13 @@ def __call__(self, environ, start_response): environ: A WSGI environment. start_response: The WSGI start_response callable. """ - req_attrs = collect_request_attributes(environ) + req_attrs = collect_request_attributes( + environ, self._sem_conv_opt_in_mode + ) active_requests_count_attrs = _parse_active_request_count_attrs( - req_attrs + req_attrs, + self._sem_conv_opt_in_mode, ) - duration_attrs = _parse_duration_attrs(req_attrs) span, token = _start_internal_or_server_span( tracer=self.tracer, @@ -582,20 +656,42 @@ def __call__(self, environ, start_response): try: with trace.use_span(span): start_response = self._create_start_response( - span, start_response, response_hook, duration_attrs + span, + start_response, + response_hook, + req_attrs, + self._sem_conv_opt_in_mode, ) iterable = self.wsgi(environ, start_response) return _end_span_after_iterating(iterable, span, token) except Exception as ex: - if span.is_recording(): + if _report_new(self._sem_conv_opt_in_mode): + req_attrs[_SPAN_ATTRIBUTES_ERROR_TYPE] = type(ex).__qualname__ + if span.is_recording(): + span.set_attribute( + _SPAN_ATTRIBUTES_ERROR_TYPE, type(ex).__qualname__ + ) span.set_status(Status(StatusCode.ERROR, str(ex))) span.end() if token is not None: context.detach(token) raise finally: - duration = max(round((default_timer() - start) * 1000), 0) - self.duration_histogram.record(duration, duration_attrs) + duration_s = default_timer() - start + if self.duration_histogram_old: + duration_attrs_old = _parse_duration_attrs( + req_attrs, _HTTPStabilityMode.DEFAULT + ) + self.duration_histogram_old.record( + max(round(duration_s * 1000), 0), duration_attrs_old + ) + if self.duration_histogram_new: + duration_attrs_new = _parse_duration_attrs( + req_attrs, _HTTPStabilityMode.HTTP + ) + self.duration_histogram_new.record( + max(duration_s, 0), duration_attrs_new + ) self.active_requests_counter.add(-1, active_requests_count_attrs) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py index 942f175da1..1bb8350a06 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py @@ -16,3 +16,5 @@ _instruments = tuple() _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/version.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/version.py index 2b23bc4994..ff4933b20b 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/version.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index 74c54f0c54..ed4afbd44e 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-lines + import sys import unittest import wsgiref.util as wsgiref_util @@ -20,6 +22,15 @@ import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import trace as trace_api +from opentelemetry.instrumentation._semconv import ( + OTEL_SEMCONV_STABILITY_OPT_IN, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _server_active_requests_count_attrs_new, + _server_active_requests_count_attrs_old, + _server_duration_attrs_new, + _server_duration_attrs_old, +) from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -127,17 +138,58 @@ def wsgi_with_repeat_custom_response_headers(environ, start_response): return [b"*"] -_expected_metric_names = [ +_expected_metric_names_old = [ "http.server.active_requests", "http.server.duration", ] -_recommended_attrs = { - "http.server.active_requests": otel_wsgi._active_requests_count_attrs, - "http.server.duration": otel_wsgi._duration_attrs, +_expected_metric_names_new = [ + "http.server.active_requests", + "http.server.request.duration", +] +_recommended_metrics_attrs_old = { + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, +} +_recommended_metrics_attrs_new = { + "http.server.active_requests": _server_active_requests_count_attrs_new, + "http.server.request.duration": _server_duration_attrs_new, +} +_server_active_requests_count_attrs_both = ( + _server_active_requests_count_attrs_old +) +_server_active_requests_count_attrs_both.extend( + _server_active_requests_count_attrs_new +) +_recommended_metrics_attrs_both = { + "http.server.active_requests": _server_active_requests_count_attrs_both, + "http.server.duration": _server_duration_attrs_old, + "http.server.request.duration": _server_duration_attrs_new, } class TestWsgiApplication(WsgiTestBase): + def setUp(self): + super().setUp() + + test_name = "" + if hasattr(self, "_testMethodName"): + test_name = self._testMethodName + sem_conv_mode = "default" + if "new_semconv" in test_name: + sem_conv_mode = "http" + elif "both_semconv" in test_name: + sem_conv_mode = "http/dup" + self.env_patch = mock.patch.dict( + "os.environ", + { + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, + }, + ) + + _OpenTelemetrySemanticConventionStability._initialized = False + + self.env_patch.start() + def validate_response( self, response, @@ -146,6 +198,8 @@ def validate_response( http_method="GET", span_attributes=None, response_headers=None, + old_sem_conv=True, + new_sem_conv=False, ): while True: try: @@ -171,7 +225,8 @@ def validate_response( self.assertEqual(len(span_list), 1) self.assertEqual(span_list[0].name, span_name) self.assertEqual(span_list[0].kind, trace_api.SpanKind.SERVER) - expected_attributes = { + expected_attributes = {} + expected_attributes_old = { SpanAttributes.HTTP_SERVER_NAME: "127.0.0.1", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, @@ -179,10 +234,28 @@ def validate_response( SpanAttributes.HTTP_FLAVOR: "1.0", SpanAttributes.HTTP_URL: "http://127.0.0.1/", SpanAttributes.HTTP_STATUS_CODE: 200, + SpanAttributes.NET_HOST_NAME: "127.0.0.1", } + expected_attributes_new = { + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.SERVER_ADDRESS: "127.0.0.1", + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200, + SpanAttributes.URL_SCHEME: "http", + } + if old_sem_conv: + expected_attributes.update(expected_attributes_old) + if new_sem_conv: + expected_attributes.update(expected_attributes_new) + expected_attributes.update(span_attributes or {}) if http_method is not None: - expected_attributes[SpanAttributes.HTTP_METHOD] = http_method + if old_sem_conv: + expected_attributes[SpanAttributes.HTTP_METHOD] = http_method + if new_sem_conv: + expected_attributes[SpanAttributes.HTTP_REQUEST_METHOD] = ( + http_method + ) self.assertEqual(span_list[0].attributes, expected_attributes) def test_basic_wsgi_call(self): @@ -190,6 +263,16 @@ def test_basic_wsgi_call(self): response = app(self.environ, self.start_response) self.validate_response(response) + def test_basic_wsgi_call_new_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) + response = app(self.environ, self.start_response) + self.validate_response(response, old_sem_conv=False, new_sem_conv=True) + + def test_basic_wsgi_call_both_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) + response = app(self.environ, self.start_response) + self.validate_response(response, old_sem_conv=True, new_sem_conv=True) + def test_hooks(self): hook_headers = ( "hook_attr", @@ -283,7 +366,38 @@ def test_wsgi_metrics(self): for scope_metric in resource_metric.scope_metrics: self.assertTrue(len(scope_metric.metrics) != 0) for metric in scope_metric.metrics: - self.assertIn(metric.name, _expected_metric_names) + self.assertIn(metric.name, _expected_metric_names_old) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_old[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_wsgi_metrics_new_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(error_wsgi_unhandled) + self.assertRaises(ValueError, app, self.environ, self.start_response) + self.assertRaises(ValueError, app, self.environ, self.start_response) + self.assertRaises(ValueError, app, self.environ, self.start_response) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names_new) data_points = list(metric.data.data_points) self.assertEqual(len(data_points), 1) for point in data_points: @@ -294,7 +408,46 @@ def test_wsgi_metrics(self): number_data_point_seen = True for attr in point.attributes: self.assertIn( - attr, _recommended_attrs[metric.name] + attr, + _recommended_metrics_attrs_new[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_wsgi_metrics_both_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(error_wsgi_unhandled) + self.assertRaises(ValueError, app, self.environ, self.start_response) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + if metric.unit == "ms": + self.assertEqual(metric.name, "http.server.duration") + elif metric.unit == "s": + self.assertEqual( + metric.name, "http.server.request.duration" + ) + else: + self.assertEqual( + metric.name, "http.server.active_requests" + ) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_both[metric.name], ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) @@ -303,7 +456,7 @@ def test_nonstandard_http_method(self): app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) response = app(self.environ, self.start_response) self.validate_response( - response, span_name="UNKNOWN /", http_method="UNKNOWN" + response, span_name="HTTP", http_method="_OTHER" ) @mock.patch.dict( @@ -349,34 +502,96 @@ def test_request_attributes(self): SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.HTTP_SERVER_NAME: "127.0.0.1", SpanAttributes.HTTP_FLAVOR: "1.0", + SpanAttributes.NET_HOST_NAME: "127.0.0.1", + }, + ) + + def test_request_attributes_new_semconv(self): + self.environ["QUERY_STRING"] = "foo=bar" + self.environ["REQUEST_URI"] = "http://127.0.0.1/?foo=bar" + + attrs = otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ) + self.assertDictEqual( + attrs, + { + SpanAttributes.HTTP_REQUEST_METHOD: "GET", + SpanAttributes.SERVER_ADDRESS: "127.0.0.1", + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", + SpanAttributes.URL_PATH: "/", + SpanAttributes.URL_QUERY: "foo=bar", + SpanAttributes.URL_SCHEME: "http", }, ) - def validate_url(self, expected_url, raw=False, has_host=True): + def validate_url( + self, + expected_url, + raw=False, + has_host=True, + old_semconv=True, + new_semconv=False, + ): parts = urlsplit(expected_url) - expected = { + expected_old = { SpanAttributes.HTTP_SCHEME: parts.scheme, SpanAttributes.NET_HOST_PORT: parts.port or (80 if parts.scheme == "http" else 443), SpanAttributes.HTTP_SERVER_NAME: parts.hostname, # Not true in the general case, but for all tests. } - if raw: - expected[SpanAttributes.HTTP_TARGET] = expected_url.split( - parts.netloc, 1 - )[1] - else: - expected[SpanAttributes.HTTP_URL] = expected_url - if has_host: - expected[SpanAttributes.HTTP_HOST] = parts.hostname + expected_new = { + SpanAttributes.SERVER_PORT: parts.port + or (80 if parts.scheme == "http" else 443), + SpanAttributes.SERVER_ADDRESS: parts.hostname, + SpanAttributes.URL_PATH: parts.path, + SpanAttributes.URL_QUERY: parts.query, + } + if old_semconv: + if raw: + expected_old[SpanAttributes.HTTP_TARGET] = expected_url.split( + parts.netloc, 1 + )[1] + else: + expected_old[SpanAttributes.HTTP_URL] = expected_url + if has_host: + expected_old[SpanAttributes.HTTP_HOST] = parts.hostname + if new_semconv: + if raw: + expected_new[SpanAttributes.URL_PATH] = expected_url.split( + parts.path, 1 + )[1] + if parts.query: + expected_new[SpanAttributes.URL_QUERY] = ( + expected_url.split(parts.query, 1)[1] + ) + else: + expected_new[SpanAttributes.HTTP_URL] = expected_url + if has_host: + expected_new[SpanAttributes.SERVER_ADDRESS] = parts.hostname attrs = otel_wsgi.collect_request_attributes(self.environ) self.assertGreaterEqual( - attrs.items(), expected.items(), expected_url + " expected." + attrs.items(), expected_old.items(), expected_url + " expected." ) def test_request_attributes_with_partial_raw_uri(self): - self.environ["RAW_URI"] = "/#top" - self.validate_url("http://127.0.0.1/#top", raw=True) + self.environ["RAW_URI"] = "/?foo=bar/#top" + self.validate_url("http://127.0.0.1/?foo=bar/#top", raw=True) + self.validate_url( + "http://127.0.0.1/?foo=bar/#top", + raw=True, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "http://127.0.0.1/?foo=bar/#top", + raw=True, + old_semconv=True, + new_semconv=True, + ) def test_request_attributes_with_partial_raw_uri_and_nonstandard_port( self, @@ -385,18 +600,68 @@ def test_request_attributes_with_partial_raw_uri_and_nonstandard_port( del self.environ["HTTP_HOST"] self.environ["SERVER_PORT"] = "8080" self.validate_url("http://127.0.0.1:8080/?", raw=True, has_host=False) + self.validate_url( + "http://127.0.0.1:8080/?", + raw=True, + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "http://127.0.0.1:8080/?", + raw=True, + has_host=False, + old_semconv=True, + new_semconv=True, + ) def test_https_uri_port(self): del self.environ["HTTP_HOST"] self.environ["SERVER_PORT"] = "443" self.environ["wsgi.url_scheme"] = "https" self.validate_url("https://127.0.0.1/", has_host=False) + self.validate_url( + "https://127.0.0.1/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) self.environ["SERVER_PORT"] = "8080" self.validate_url("https://127.0.0.1:8080/", has_host=False) + self.validate_url( + "https://127.0.0.1:8080/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1:8080/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) self.environ["SERVER_PORT"] = "80" self.validate_url("https://127.0.0.1:80/", has_host=False) + self.validate_url( + "https://127.0.0.1:80/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1:80/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) def test_http_uri_port(self): del self.environ["HTTP_HOST"] @@ -438,40 +703,69 @@ def test_request_attributes_with_faux_scheme_relative_raw_uri(self): def test_request_attributes_pathless(self): self.environ["RAW_URI"] = "" - expected = {SpanAttributes.HTTP_TARGET: ""} - self.assertGreaterEqual( - otel_wsgi.collect_request_attributes(self.environ).items(), - expected.items(), + self.assertIsNone( + otel_wsgi.collect_request_attributes(self.environ).get( + SpanAttributes.HTTP_TARGET + ) ) def test_request_attributes_with_full_request_uri(self): self.environ["HTTP_HOST"] = "127.0.0.1:8080" self.environ["REQUEST_METHOD"] = "CONNECT" - self.environ[ - "REQUEST_URI" - ] = "127.0.0.1:8080" # Might happen in a CONNECT request - expected = { + self.environ["REQUEST_URI"] = ( + "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing" # Might happen in a CONNECT request + ) + expected_old = { SpanAttributes.HTTP_HOST: "127.0.0.1:8080", - SpanAttributes.HTTP_TARGET: "127.0.0.1:8080", + SpanAttributes.HTTP_TARGET: "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing", + } + expected_new = { + SpanAttributes.URL_PATH: "/3/library/urllib.parse.html", + SpanAttributes.URL_QUERY: "highlight=params", } self.assertGreaterEqual( otel_wsgi.collect_request_attributes(self.environ).items(), - expected.items(), + expected_old.items(), + ) + self.assertGreaterEqual( + otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ).items(), + expected_new.items(), ) def test_http_user_agent_attribute(self): self.environ["HTTP_USER_AGENT"] = "test-useragent" expected = {SpanAttributes.HTTP_USER_AGENT: "test-useragent"} + expected_new = {SpanAttributes.USER_AGENT_ORIGINAL: "test-useragent"} self.assertGreaterEqual( otel_wsgi.collect_request_attributes(self.environ).items(), expected.items(), ) + self.assertGreaterEqual( + otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ).items(), + expected_new.items(), + ) def test_response_attributes(self): otel_wsgi.add_response_attributes(self.span, "404 Not Found", {}) + otel_wsgi.add_response_attributes( + self.span, + "404 Not Found", + {}, + sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP, + ) expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),) - self.assertEqual(self.span.set_attribute.call_count, len(expected)) + expected_new = ( + mock.call(SpanAttributes.HTTP_RESPONSE_STATUS_CODE, 404), + ) + self.assertEqual(self.span.set_attribute.call_count, 2) self.span.set_attribute.assert_has_calls(expected, any_order=True) + self.span.set_attribute.assert_has_calls(expected_new, any_order=True) def test_credential_removal(self): self.environ["HTTP_HOST"] = "username:password@mock" diff --git a/opentelemetry-contrib-instrumentations/LICENSE b/opentelemetry-contrib-instrumentations/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/opentelemetry-contrib-instrumentations/LICENSE +++ b/opentelemetry-contrib-instrumentations/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index 1cd2c37625..7e4afad6f7 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -28,53 +28,54 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ - "opentelemetry-instrumentation-aio-pika==0.45b0.dev", - "opentelemetry-instrumentation-aiohttp-client==0.45b0.dev", - "opentelemetry-instrumentation-aiohttp-server==0.45b0.dev", - "opentelemetry-instrumentation-aiopg==0.45b0.dev", - "opentelemetry-instrumentation-asgi==0.45b0.dev", - "opentelemetry-instrumentation-asyncio==0.45b0.dev", - "opentelemetry-instrumentation-asyncpg==0.45b0.dev", - "opentelemetry-instrumentation-aws-lambda==0.45b0.dev", - "opentelemetry-instrumentation-boto==0.45b0.dev", - "opentelemetry-instrumentation-boto3sqs==0.45b0.dev", - "opentelemetry-instrumentation-botocore==0.45b0.dev", - "opentelemetry-instrumentation-cassandra==0.45b0.dev", - "opentelemetry-instrumentation-celery==0.45b0.dev", - "opentelemetry-instrumentation-confluent-kafka==0.45b0.dev", - "opentelemetry-instrumentation-dbapi==0.45b0.dev", - "opentelemetry-instrumentation-django==0.45b0.dev", - "opentelemetry-instrumentation-elasticsearch==0.45b0.dev", - "opentelemetry-instrumentation-falcon==0.45b0.dev", - "opentelemetry-instrumentation-fastapi==0.45b0.dev", - "opentelemetry-instrumentation-flask==0.45b0.dev", - "opentelemetry-instrumentation-grpc==0.45b0.dev", - "opentelemetry-instrumentation-httpx==0.45b0.dev", - "opentelemetry-instrumentation-jinja2==0.45b0.dev", - "opentelemetry-instrumentation-kafka-python==0.45b0.dev", - "opentelemetry-instrumentation-logging==0.45b0.dev", - "opentelemetry-instrumentation-mysql==0.45b0.dev", - "opentelemetry-instrumentation-mysqlclient==0.45b0.dev", - "opentelemetry-instrumentation-pika==0.45b0.dev", - "opentelemetry-instrumentation-psycopg==0.45b0.dev", - "opentelemetry-instrumentation-psycopg2==0.45b0.dev", - "opentelemetry-instrumentation-pymemcache==0.45b0.dev", - "opentelemetry-instrumentation-pymongo==0.45b0.dev", - "opentelemetry-instrumentation-pymysql==0.45b0.dev", - "opentelemetry-instrumentation-pyramid==0.45b0.dev", - "opentelemetry-instrumentation-redis==0.45b0.dev", - "opentelemetry-instrumentation-remoulade==0.45b0.dev", - "opentelemetry-instrumentation-requests==0.45b0.dev", - "opentelemetry-instrumentation-sklearn==0.45b0.dev", - "opentelemetry-instrumentation-sqlalchemy==0.45b0.dev", - "opentelemetry-instrumentation-sqlite3==0.45b0.dev", - "opentelemetry-instrumentation-starlette==0.45b0.dev", - "opentelemetry-instrumentation-system-metrics==0.45b0.dev", - "opentelemetry-instrumentation-tornado==0.45b0.dev", - "opentelemetry-instrumentation-tortoiseorm==0.45b0.dev", - "opentelemetry-instrumentation-urllib==0.45b0.dev", - "opentelemetry-instrumentation-urllib3==0.45b0.dev", - "opentelemetry-instrumentation-wsgi==0.45b0.dev", + "opentelemetry-instrumentation-aio-pika==0.46b0.dev", + "opentelemetry-instrumentation-aiohttp-client==0.46b0.dev", + "opentelemetry-instrumentation-aiohttp-server==0.46b0.dev", + "opentelemetry-instrumentation-aiopg==0.46b0.dev", + "opentelemetry-instrumentation-asgi==0.46b0.dev", + "opentelemetry-instrumentation-asyncio==0.46b0.dev", + "opentelemetry-instrumentation-asyncpg==0.46b0.dev", + "opentelemetry-instrumentation-aws-lambda==0.46b0.dev", + "opentelemetry-instrumentation-boto==0.46b0.dev", + "opentelemetry-instrumentation-boto3sqs==0.46b0.dev", + "opentelemetry-instrumentation-botocore==0.46b0.dev", + "opentelemetry-instrumentation-cassandra==0.46b0.dev", + "opentelemetry-instrumentation-celery==0.46b0.dev", + "opentelemetry-instrumentation-confluent-kafka==0.46b0.dev", + "opentelemetry-instrumentation-dbapi==0.46b0.dev", + "opentelemetry-instrumentation-django==0.46b0.dev", + "opentelemetry-instrumentation-elasticsearch==0.46b0.dev", + "opentelemetry-instrumentation-falcon==0.46b0.dev", + "opentelemetry-instrumentation-fastapi==0.46b0.dev", + "opentelemetry-instrumentation-flask==0.46b0.dev", + "opentelemetry-instrumentation-grpc==0.46b0.dev", + "opentelemetry-instrumentation-httpx==0.46b0.dev", + "opentelemetry-instrumentation-jinja2==0.46b0.dev", + "opentelemetry-instrumentation-kafka-python==0.46b0.dev", + "opentelemetry-instrumentation-logging==0.46b0.dev", + "opentelemetry-instrumentation-mysql==0.46b0.dev", + "opentelemetry-instrumentation-mysqlclient==0.46b0.dev", + "opentelemetry-instrumentation-pika==0.46b0.dev", + "opentelemetry-instrumentation-psycopg==0.46b0.dev", + "opentelemetry-instrumentation-psycopg2==0.46b0.dev", + "opentelemetry-instrumentation-pymemcache==0.46b0.dev", + "opentelemetry-instrumentation-pymongo==0.46b0.dev", + "opentelemetry-instrumentation-pymysql==0.46b0.dev", + "opentelemetry-instrumentation-pyramid==0.46b0.dev", + "opentelemetry-instrumentation-redis==0.46b0.dev", + "opentelemetry-instrumentation-remoulade==0.46b0.dev", + "opentelemetry-instrumentation-requests==0.46b0.dev", + "opentelemetry-instrumentation-sklearn==0.46b0.dev", + "opentelemetry-instrumentation-sqlalchemy==0.46b0.dev", + "opentelemetry-instrumentation-sqlite3==0.46b0.dev", + "opentelemetry-instrumentation-starlette==0.46b0.dev", + "opentelemetry-instrumentation-system-metrics==0.46b0.dev", + "opentelemetry-instrumentation-threading==0.46b0.dev", + "opentelemetry-instrumentation-tornado==0.46b0.dev", + "opentelemetry-instrumentation-tortoiseorm==0.46b0.dev", + "opentelemetry-instrumentation-urllib==0.46b0.dev", + "opentelemetry-instrumentation-urllib3==0.46b0.dev", + "opentelemetry-instrumentation-wsgi==0.46b0.dev", ] [project.urls] diff --git a/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py b/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py index 2b23bc4994..ff4933b20b 100644 --- a/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py +++ b/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/opentelemetry-distro/pyproject.toml b/opentelemetry-distro/pyproject.toml index 43c646b1d9..0cec60a63f 100644 --- a/opentelemetry-distro/pyproject.toml +++ b/opentelemetry-distro/pyproject.toml @@ -23,15 +23,14 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.45b0.dev", + "opentelemetry-instrumentation == 0.46b0.dev", "opentelemetry-sdk ~= 1.13", ] [project.optional-dependencies] otlp = [ - "opentelemetry-exporter-otlp == 1.24.0.dev", + "opentelemetry-exporter-otlp == 1.25.0.dev", ] -test = [] [project.entry-points.opentelemetry_configurator] configurator = "opentelemetry.distro:OpenTelemetryConfigurator" diff --git a/opentelemetry-distro/src/opentelemetry/distro/version.py b/opentelemetry-distro/src/opentelemetry/distro/version.py index 2b23bc4994..ff4933b20b 100644 --- a/opentelemetry-distro/src/opentelemetry/distro/version.py +++ b/opentelemetry-distro/src/opentelemetry/distro/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/opentelemetry-distro/test-requirements.txt b/opentelemetry-distro/test-requirements.txt new file mode 100644 index 0000000000..978389dc9a --- /dev/null +++ b/opentelemetry-distro/test-requirements.txt @@ -0,0 +1,17 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e opentelemetry-distro diff --git a/opentelemetry-instrumentation/LICENSE b/opentelemetry-instrumentation/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/opentelemetry-instrumentation/LICENSE +++ b/opentelemetry-instrumentation/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/opentelemetry-instrumentation/pyproject.toml b/opentelemetry-instrumentation/pyproject.toml index db389544c9..a20b005911 100644 --- a/opentelemetry-instrumentation/pyproject.toml +++ b/opentelemetry-instrumentation/pyproject.toml @@ -29,9 +29,6 @@ dependencies = [ "wrapt >= 1.0.0, < 2.0.0", ] -[project.optional-dependencies] -test = [] - [project.scripts] opentelemetry-bootstrap = "opentelemetry.instrumentation.bootstrap:run" opentelemetry-instrument = "opentelemetry.instrumentation.auto_instrumentation:run" diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index fbfc92cf21..efe3c75f70 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -16,13 +16,16 @@ import threading from enum import Enum +from opentelemetry.instrumentation.utils import http_status_to_status_code from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace.status import Status, StatusCode # TODO: will come through semconv package once updated _SPAN_ATTRIBUTES_ERROR_TYPE = "error.type" _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS = "network.peer.address" _SPAN_ATTRIBUTES_NETWORK_PEER_PORT = "network.peer.port" _METRIC_ATTRIBUTES_CLIENT_DURATION_NAME = "http.client.request.duration" +_METRIC_ATTRIBUTES_SERVER_DURATION_NAME = "http.server.request.duration" _client_duration_attrs_old = [ SpanAttributes.HTTP_STATUS_CODE, @@ -45,13 +48,116 @@ # SpanAttributes.URL_SCHEME, ] +_server_duration_attrs_old = [ + SpanAttributes.HTTP_METHOD, + SpanAttributes.HTTP_HOST, + SpanAttributes.HTTP_SCHEME, + SpanAttributes.HTTP_STATUS_CODE, + SpanAttributes.HTTP_FLAVOR, + SpanAttributes.HTTP_SERVER_NAME, + SpanAttributes.NET_HOST_NAME, + SpanAttributes.NET_HOST_PORT, +] + +_server_duration_attrs_new = [ + _SPAN_ATTRIBUTES_ERROR_TYPE, + SpanAttributes.HTTP_REQUEST_METHOD, + SpanAttributes.HTTP_RESPONSE_STATUS_CODE, + SpanAttributes.HTTP_ROUTE, + SpanAttributes.NETWORK_PROTOCOL_VERSION, + SpanAttributes.URL_SCHEME, +] + +_server_active_requests_count_attrs_old = [ + SpanAttributes.HTTP_METHOD, + SpanAttributes.HTTP_HOST, + SpanAttributes.HTTP_SCHEME, + SpanAttributes.HTTP_FLAVOR, + SpanAttributes.HTTP_SERVER_NAME, + SpanAttributes.NET_HOST_NAME, + SpanAttributes.NET_HOST_PORT, +] + +_server_active_requests_count_attrs_new = [ + SpanAttributes.HTTP_REQUEST_METHOD, + SpanAttributes.URL_SCHEME, +] + +OTEL_SEMCONV_STABILITY_OPT_IN = "OTEL_SEMCONV_STABILITY_OPT_IN" + + +class _OpenTelemetryStabilitySignalType: + HTTP = "http" + + +class _HTTPStabilityMode(Enum): + # http - emit the new, stable HTTP and networking conventions ONLY + HTTP = "http" + # http/dup - emit both the old and the stable HTTP and networking conventions + HTTP_DUP = "http/dup" + # default - continue emitting old experimental HTTP and networking conventions + DEFAULT = "default" + + +def _report_new(mode): + return mode.name != _HTTPStabilityMode.DEFAULT.name + + +def _report_old(mode): + return mode.name != _HTTPStabilityMode.HTTP.name + + +class _OpenTelemetrySemanticConventionStability: + _initialized = False + _lock = threading.Lock() + _OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {} + + @classmethod + def _initialize(cls): + with _OpenTelemetrySemanticConventionStability._lock: + if not _OpenTelemetrySemanticConventionStability._initialized: + # Users can pass in comma delimited string for opt-in options + # Only values for http stability are supported for now + opt_in = os.environ.get(OTEL_SEMCONV_STABILITY_OPT_IN, "") + opt_in_list = [] + if opt_in: + opt_in_list = [s.strip() for s in opt_in.split(",")] + http_opt_in = _HTTPStabilityMode.DEFAULT + if opt_in_list: + # Process http opt-in + # http/dup takes priority over http + if _HTTPStabilityMode.HTTP_DUP.value in opt_in_list: + http_opt_in = _HTTPStabilityMode.HTTP_DUP + elif _HTTPStabilityMode.HTTP.value in opt_in_list: + http_opt_in = _HTTPStabilityMode.HTTP + _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[ + _OpenTelemetryStabilitySignalType.HTTP + ] = http_opt_in + _OpenTelemetrySemanticConventionStability._initialized = True -def _filter_duration_attrs(attrs, sem_conv_opt_in_mode): + @classmethod + # Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.) + def _get_opentelemetry_stability_opt_in_mode( + cls, + signal_type: _OpenTelemetryStabilitySignalType, + ) -> _HTTPStabilityMode: + return _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get( + signal_type, _HTTPStabilityMode.DEFAULT + ) + + +def _filter_semconv_duration_attrs( + attrs, + old_attrs, + new_attrs, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): filtered_attrs = {} + # duration is two different metrics depending on sem_conv_opt_in_mode, so no DUP attributes allowed_attributes = ( - _client_duration_attrs_new - if sem_conv_opt_in_mode == _OpenTelemetryStabilityMode.HTTP - else _client_duration_attrs_old + new_attrs + if sem_conv_opt_in_mode == _HTTPStabilityMode.HTTP + else old_attrs ) for key, val in attrs.items(): if key in allowed_attributes: @@ -59,6 +165,24 @@ def _filter_duration_attrs(attrs, sem_conv_opt_in_mode): return filtered_attrs +def _filter_semconv_active_request_count_attr( + attrs, + old_attrs, + new_attrs, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): + filtered_attrs = {} + if _report_old(sem_conv_opt_in_mode): + for key, val in attrs.items(): + if key in old_attrs: + filtered_attrs[key] = val + if _report_new(sem_conv_opt_in_mode): + for key, val in attrs.items(): + if key in new_attrs: + filtered_attrs[key] = val + return filtered_attrs + + def set_string_attribute(result, key, value): if value: result[key] = value @@ -90,6 +214,15 @@ def _set_http_method(result, original, normalized, sem_conv_opt_in_mode): ) +def _set_http_status_code(result, code, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.HTTP_STATUS_CODE, code) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute( + result, SpanAttributes.HTTP_RESPONSE_STATUS_CODE, code + ) + + def _set_http_url(result, url, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_URL, url) @@ -100,41 +233,34 @@ def _set_http_url(result, url, sem_conv_opt_in_mode): def _set_http_scheme(result, scheme, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_SCHEME, scheme) - # TODO: Support opt-in for scheme in new semconv - # if _report_new(sem_conv_opt_in_mode): - # set_string_attribute(result, SpanAttributes.URL_SCHEME, scheme) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.URL_SCHEME, scheme) -def _set_http_hostname(result, hostname, sem_conv_opt_in_mode): +def _set_http_host(result, host, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): - set_string_attribute(result, SpanAttributes.HTTP_HOST, hostname) + set_string_attribute(result, SpanAttributes.HTTP_HOST, host) if _report_new(sem_conv_opt_in_mode): - set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, hostname) + set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, host) + +# Client -def _set_http_net_peer_name(result, peer_name, sem_conv_opt_in_mode): + +def _set_http_net_peer_name_client(result, peer_name, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.NET_PEER_NAME, peer_name) if _report_new(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, peer_name) -def _set_http_port(result, port, sem_conv_opt_in_mode): +def _set_http_peer_port_client(result, port, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_int_attribute(result, SpanAttributes.NET_PEER_PORT, port) if _report_new(sem_conv_opt_in_mode): set_int_attribute(result, SpanAttributes.SERVER_PORT, port) -def _set_http_status_code(result, code, sem_conv_opt_in_mode): - if _report_old(sem_conv_opt_in_mode): - set_int_attribute(result, SpanAttributes.HTTP_STATUS_CODE, code) - if _report_new(sem_conv_opt_in_mode): - set_int_attribute( - result, SpanAttributes.HTTP_RESPONSE_STATUS_CODE, code - ) - - def _set_http_network_protocol_version(result, version, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_FLAVOR, version) @@ -144,74 +270,117 @@ def _set_http_network_protocol_version(result, version, sem_conv_opt_in_mode): ) -_OTEL_SEMCONV_STABILITY_OPT_IN_KEY = "OTEL_SEMCONV_STABILITY_OPT_IN" +# Server -class _OpenTelemetryStabilitySignalType: - HTTP = "http" +def _set_http_net_host(result, host, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_HOST_NAME, host) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, host) -class _OpenTelemetryStabilityMode(Enum): - # http - emit the new, stable HTTP and networking conventions ONLY - HTTP = "http" - # http/dup - emit both the old and the stable HTTP and networking conventions - HTTP_DUP = "http/dup" - # default - continue emitting old experimental HTTP and networking conventions - DEFAULT = "default" +def _set_http_net_host_port(result, port, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.NET_HOST_PORT, port) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.SERVER_PORT, port) -def _report_new(mode): - return mode.name != _OpenTelemetryStabilityMode.DEFAULT.name +def _set_http_target(result, target, path, query, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.HTTP_TARGET, target) + if _report_new(sem_conv_opt_in_mode): + if path: + set_string_attribute(result, SpanAttributes.URL_PATH, path) + if query: + set_string_attribute(result, SpanAttributes.URL_QUERY, query) -def _report_old(mode): - return mode.name != _OpenTelemetryStabilityMode.HTTP.name +def _set_http_peer_ip(result, ip, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_PEER_IP, ip) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.CLIENT_ADDRESS, ip) -class _OpenTelemetrySemanticConventionStability: - _initialized = False - _lock = threading.Lock() - _OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {} +def _set_http_peer_port_server(result, port, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.NET_PEER_PORT, port) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.CLIENT_PORT, port) - @classmethod - def _initialize(cls): - with _OpenTelemetrySemanticConventionStability._lock: - if not _OpenTelemetrySemanticConventionStability._initialized: - # Users can pass in comma delimited string for opt-in options - # Only values for http stability are supported for now - opt_in = os.environ.get(_OTEL_SEMCONV_STABILITY_OPT_IN_KEY, "") - opt_in_list = [] - if opt_in: - opt_in_list = [s.strip() for s in opt_in.split(",")] - http_opt_in = _OpenTelemetryStabilityMode.DEFAULT - if opt_in_list: - # Process http opt-in - # http/dup takes priority over http - if ( - _OpenTelemetryStabilityMode.HTTP_DUP.value - in opt_in_list - ): - http_opt_in = _OpenTelemetryStabilityMode.HTTP_DUP - elif _OpenTelemetryStabilityMode.HTTP.value in opt_in_list: - http_opt_in = _OpenTelemetryStabilityMode.HTTP - _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[ - _OpenTelemetryStabilitySignalType.HTTP - ] = http_opt_in - _OpenTelemetrySemanticConventionStability._initialized = True - @classmethod - # Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.) - def _get_opentelemetry_stability_opt_in_mode( - cls, - signal_type: _OpenTelemetryStabilitySignalType, - ) -> _OpenTelemetryStabilityMode: - return _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get( - signal_type, _OpenTelemetryStabilityMode.DEFAULT +def _set_http_user_agent(result, user_agent, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.HTTP_USER_AGENT, user_agent + ) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.USER_AGENT_ORIGINAL, user_agent + ) + + +def _set_http_net_peer_name_server(result, name, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_PEER_NAME, name) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.CLIENT_ADDRESS, name) + + +def _set_http_flavor_version(result, version, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.HTTP_FLAVOR, version) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.NETWORK_PROTOCOL_VERSION, version + ) + + +def _set_status( + span, + metrics_attributes, + status_code_str, + status_code, + sem_conv_opt_in_mode, +): + if status_code < 0: + if _report_new(sem_conv_opt_in_mode): + span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str) + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = status_code_str + + span.set_status( + Status( + StatusCode.ERROR, + "Non-integer HTTP status: " + status_code_str, + ) ) + else: + status = http_status_to_status_code(status_code, server_span=True) + + if _report_old(sem_conv_opt_in_mode): + span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) + metrics_attributes[SpanAttributes.HTTP_STATUS_CODE] = status_code + if _report_new(sem_conv_opt_in_mode): + span.set_attribute( + SpanAttributes.HTTP_RESPONSE_STATUS_CODE, status_code + ) + metrics_attributes[SpanAttributes.HTTP_RESPONSE_STATUS_CODE] = ( + status_code + ) + if status == StatusCode.ERROR: + span.set_attribute( + _SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str + ) + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = ( + status_code_str + ) + span.set_status(Status(status)) # Get schema version based off of opt-in mode -def _get_schema_url(mode: _OpenTelemetryStabilityMode) -> str: - if mode is _OpenTelemetryStabilityMode.DEFAULT: +def _get_schema_url(mode: _HTTPStabilityMode) -> str: + if mode is _HTTPStabilityMode.DEFAULT: return "https://opentelemetry.io/schemas/1.11.0" return SpanAttributes.SCHEMA_URL diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 3591581c97..9eebd5bb38 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -18,179 +18,180 @@ libraries = [ { "library": "aio_pika >= 7.2.0, < 10.0.0", - "instrumentation": "opentelemetry-instrumentation-aio-pika==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-aio-pika==0.46b0.dev", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.46b0.dev", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.46b0.dev", }, { "library": "aiopg >= 0.13.0, < 2.0.0", - "instrumentation": "opentelemetry-instrumentation-aiopg==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-aiopg==0.46b0.dev", }, { "library": "asgiref ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-asgi==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-asgi==0.46b0.dev", }, { "library": "asyncpg >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-asyncpg==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-asyncpg==0.46b0.dev", }, { "library": "boto~=2.0", - "instrumentation": "opentelemetry-instrumentation-boto==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-boto==0.46b0.dev", }, { "library": "boto3 ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.46b0.dev", }, { "library": "botocore ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-botocore==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-botocore==0.46b0.dev", }, { "library": "cassandra-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.46b0.dev", }, { "library": "scylla-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.46b0.dev", }, { "library": "celery >= 4.0, < 6.0", - "instrumentation": "opentelemetry-instrumentation-celery==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-celery==0.46b0.dev", }, { "library": "confluent-kafka >= 1.8.2, <= 2.3.0", - "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.46b0.dev", }, { "library": "django >= 1.10", - "instrumentation": "opentelemetry-instrumentation-django==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-django==0.46b0.dev", }, { - "library": "elasticsearch >= 2.0", - "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.45b0.dev", + "library": "elasticsearch >= 6.0", + "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.46b0.dev", }, { "library": "falcon >= 1.4.1, < 3.1.2", - "instrumentation": "opentelemetry-instrumentation-falcon==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-falcon==0.46b0.dev", }, { "library": "fastapi ~= 0.58", - "instrumentation": "opentelemetry-instrumentation-fastapi==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-fastapi==0.46b0.dev", }, { "library": "flask >= 1.0", - "instrumentation": "opentelemetry-instrumentation-flask==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-flask==0.46b0.dev", }, { "library": "grpcio ~= 1.27", - "instrumentation": "opentelemetry-instrumentation-grpc==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-grpc==0.46b0.dev", }, { "library": "httpx >= 0.18.0", - "instrumentation": "opentelemetry-instrumentation-httpx==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-httpx==0.46b0.dev", }, { "library": "jinja2 >= 2.7, < 4.0", - "instrumentation": "opentelemetry-instrumentation-jinja2==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-jinja2==0.46b0.dev", }, { "library": "kafka-python >= 2.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.46b0.dev", }, { "library": "mysql-connector-python ~= 8.0", - "instrumentation": "opentelemetry-instrumentation-mysql==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-mysql==0.46b0.dev", }, { "library": "mysqlclient < 3", - "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.46b0.dev", }, { "library": "pika >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-pika==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-pika==0.46b0.dev", }, { "library": "psycopg >= 3.1.0", - "instrumentation": "opentelemetry-instrumentation-psycopg==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-psycopg==0.46b0.dev", }, { "library": "psycopg2 >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.46b0.dev", }, { "library": "pymemcache >= 1.3.5, < 5", - "instrumentation": "opentelemetry-instrumentation-pymemcache==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymemcache==0.46b0.dev", }, { "library": "pymongo >= 3.1, < 5.0", - "instrumentation": "opentelemetry-instrumentation-pymongo==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymongo==0.46b0.dev", }, { "library": "PyMySQL < 2", - "instrumentation": "opentelemetry-instrumentation-pymysql==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-pymysql==0.46b0.dev", }, { "library": "pyramid >= 1.7", - "instrumentation": "opentelemetry-instrumentation-pyramid==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-pyramid==0.46b0.dev", }, { "library": "redis >= 2.6", - "instrumentation": "opentelemetry-instrumentation-redis==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-redis==0.46b0.dev", }, { "library": "remoulade >= 0.50", - "instrumentation": "opentelemetry-instrumentation-remoulade==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-remoulade==0.46b0.dev", }, { "library": "requests ~= 2.0", - "instrumentation": "opentelemetry-instrumentation-requests==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-requests==0.46b0.dev", }, { "library": "scikit-learn ~= 0.24.0", - "instrumentation": "opentelemetry-instrumentation-sklearn==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-sklearn==0.46b0.dev", }, { "library": "sqlalchemy", - "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.46b0.dev", }, { "library": "starlette ~= 0.13.0", - "instrumentation": "opentelemetry-instrumentation-starlette==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-starlette==0.46b0.dev", }, { "library": "psutil >= 5", - "instrumentation": "opentelemetry-instrumentation-system-metrics==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-system-metrics==0.46b0.dev", }, { "library": "tornado >= 5.1.1", - "instrumentation": "opentelemetry-instrumentation-tornado==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-tornado==0.46b0.dev", }, { "library": "tortoise-orm >= 0.17.0", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.46b0.dev", }, { "library": "pydantic >= 1.10.2", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.46b0.dev", }, { "library": "urllib3 >= 1.0.0, < 3.0.0", - "instrumentation": "opentelemetry-instrumentation-urllib3==0.45b0.dev", + "instrumentation": "opentelemetry-instrumentation-urllib3==0.46b0.dev", }, ] default_instrumentations = [ - "opentelemetry-instrumentation-asyncio==0.45b0.dev", - "opentelemetry-instrumentation-aws-lambda==0.45b0.dev", - "opentelemetry-instrumentation-dbapi==0.45b0.dev", - "opentelemetry-instrumentation-logging==0.45b0.dev", - "opentelemetry-instrumentation-sqlite3==0.45b0.dev", - "opentelemetry-instrumentation-urllib==0.45b0.dev", - "opentelemetry-instrumentation-wsgi==0.45b0.dev", + "opentelemetry-instrumentation-asyncio==0.46b0.dev", + "opentelemetry-instrumentation-aws-lambda==0.46b0.dev", + "opentelemetry-instrumentation-dbapi==0.46b0.dev", + "opentelemetry-instrumentation-logging==0.46b0.dev", + "opentelemetry-instrumentation-sqlite3==0.46b0.dev", + "opentelemetry-instrumentation-threading==0.46b0.dev", + "opentelemetry-instrumentation-urllib==0.46b0.dev", + "opentelemetry-instrumentation-wsgi==0.46b0.dev", ] diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py index 2b23bc4994..ff4933b20b 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/opentelemetry-instrumentation/test-requirements.txt b/opentelemetry-instrumentation/test-requirements.txt new file mode 100644 index 0000000000..473a423bda --- /dev/null +++ b/opentelemetry-instrumentation/test-requirements.txt @@ -0,0 +1,16 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation diff --git a/processor/opentelemetry-processor-baggage/LICENSE b/processor/opentelemetry-processor-baggage/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/processor/opentelemetry-processor-baggage/LICENSE @@ -0,0 +1,201 @@ + 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. diff --git a/processor/opentelemetry-processor-baggage/README.rst b/processor/opentelemetry-processor-baggage/README.rst new file mode 100644 index 0000000000..2768758a99 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/README.rst @@ -0,0 +1,22 @@ +OpenTelemetry Baggage Span Processor +==================================== + +The BaggageSpanProcessor reads entries stored in Baggage +from the parent context and adds the baggage entries' keys and +values to the span as attributes on span start. + +Add this span processor to a tracer provider. + +Keys and values added to Baggage will appear on subsequent child +spans for a trace within this service *and* be propagated to external +services in accordance with any configured propagation formats +configured. If the external services also have a Baggage span +processor, the keys and values will appear in those child spans as +well. + +⚠ Warning ⚠️ + +Do not put sensitive information in Baggage. + +To repeat: a consequence of adding data to Baggage is that the keys and +values will appear in all outgoing HTTP headers from the application. diff --git a/processor/opentelemetry-processor-baggage/pyproject.toml b/processor/opentelemetry-processor-baggage/pyproject.toml new file mode 100644 index 0000000000..0ef5392fdb --- /dev/null +++ b/processor/opentelemetry-processor-baggage/pyproject.toml @@ -0,0 +1,44 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-processor-baggage" +dynamic = ["version"] +description = "OpenTelemetry Baggage Span Processor" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.8" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "opentelemetry-api ~= 1.5", + "wrapt >= 1.0.0, < 2.0.0", +] + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/processor/opentelemetry-processor-baggage" + +[tool.hatch.version] +path = "src/opentelemetry/processor/baggage/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py new file mode 100644 index 0000000000..a740c66491 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py @@ -0,0 +1,20 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=import-error + +from .processor import BaggageSpanProcessor +from .version import __version__ + +__all__ = ["BaggageSpanProcessor", "__version__"] diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py new file mode 100644 index 0000000000..36df06a94c --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py @@ -0,0 +1,55 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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 typing import Optional + +from opentelemetry.baggage import get_all as get_all_baggage +from opentelemetry.context import Context +from opentelemetry.sdk.trace.export import SpanProcessor +from opentelemetry.trace import Span + + +class BaggageSpanProcessor(SpanProcessor): + """ + The BaggageSpanProcessor reads entries stored in Baggage + from the parent context and adds the baggage entries' keys and + values to the span as attributes on span start. + + Add this span processor to a tracer provider. + + Keys and values added to Baggage will appear on subsequent child + spans for a trace within this service *and* be propagated to external + services in accordance with any configured propagation formats + configured. If the external services also have a Baggage span + processor, the keys and values will appear in those child spans as + well. + + ⚠ Warning ⚠️ + + Do not put sensitive information in Baggage. + + To repeat: a consequence of adding data to Baggage is that the keys and + values will appear in all outgoing HTTP headers from the application. + + """ + + def __init__(self) -> None: + pass + + def on_start( + self, span: "Span", parent_context: Optional[Context] = None + ) -> None: + baggage = get_all_baggage(parent_context) + for key, value in baggage.items(): + span.set_attribute(key, value) diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py new file mode 100644 index 0000000000..ff4933b20b --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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__ = "0.46b0.dev" diff --git a/processor/opentelemetry-processor-baggage/test-requirements.txt b/processor/opentelemetry-processor-baggage/test-requirements.txt new file mode 100644 index 0000000000..fa7ad3d793 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/test-requirements.txt @@ -0,0 +1,2 @@ + +-e processor/opentelemetry-processor-baggage \ No newline at end of file diff --git a/processor/opentelemetry-processor-baggage/tests/__init__.py b/processor/opentelemetry-processor-baggage/tests/__init__.py new file mode 100644 index 0000000000..b0a6f42841 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py b/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py new file mode 100644 index 0000000000..63a71c3cba --- /dev/null +++ b/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py @@ -0,0 +1,89 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from opentelemetry.baggage import get_all as get_all_baggage +from opentelemetry.baggage import set_baggage +from opentelemetry.context import attach, detach +from opentelemetry.processor.baggage import BaggageSpanProcessor +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import SpanProcessor +from opentelemetry.trace import Span, Tracer + + +class BaggageSpanProcessorTest(unittest.TestCase): + def test_check_the_baggage(self): + self.assertIsInstance(BaggageSpanProcessor(), SpanProcessor) + + def test_set_baggage_attaches_to_child_spans_and_detaches_properly_with_context( + self, + ): + tracer_provider = TracerProvider() + tracer_provider.add_span_processor(BaggageSpanProcessor()) + + # tracer has no baggage to start + tracer = tracer_provider.get_tracer("my-tracer") + self.assertIsInstance(tracer, Tracer) + self.assertEqual(get_all_baggage(), {}) + # set baggage in context + ctx = set_baggage("queen", "bee") + with tracer.start_as_current_span( + name="bumble", context=ctx + ) as bumble_span: + # span should have baggage key-value pair in context + self.assertEqual(get_all_baggage(ctx), {"queen": "bee"}) + # span should have baggage key-value pair in attribute + self.assertEqual(bumble_span._attributes["queen"], "bee") + with tracer.start_as_current_span( + name="child_span", context=ctx + ) as child_span: + self.assertIsInstance(child_span, Span) + # child span should have baggage key-value pair in context + self.assertEqual(get_all_baggage(ctx), {"queen": "bee"}) + # child span should have baggage key-value pair in attribute + self.assertEqual(child_span._attributes["queen"], "bee") + + def test_set_baggage_attaches_to_child_spans_and_detaches_properly_with_token( + self, + ): + tracer_provider = TracerProvider() + tracer_provider.add_span_processor(BaggageSpanProcessor()) + + # tracer has no baggage to start + tracer = tracer_provider.get_tracer("my-tracer") + self.assertIsInstance(tracer, Tracer) + self.assertEqual(get_all_baggage(), {}) + # create a context token and set baggage + honey_token = attach(set_baggage("bumble", "bee")) + self.assertEqual(get_all_baggage(), {"bumble": "bee"}) + # in a new span, ensure the baggage is there + with tracer.start_as_current_span("parent") as span: + self.assertEqual(get_all_baggage(), {"bumble": "bee"}) + self.assertEqual(span._attributes["bumble"], "bee") + # create a second context token and set more baggage + moar_token = attach(set_baggage("moar", "bee")) + self.assertEqual( + get_all_baggage(), {"bumble": "bee", "moar": "bee"} + ) + # in a child span, ensure all baggage is there as attributes + with tracer.start_as_current_span("child") as child_span: + self.assertEqual( + get_all_baggage(), {"bumble": "bee", "moar": "bee"} + ) + self.assertEqual(child_span._attributes["bumble"], "bee") + self.assertEqual(child_span._attributes["moar"], "bee") + detach(moar_token) + detach(honey_token) + self.assertEqual(get_all_baggage(), {}) diff --git a/propagator/opentelemetry-propagator-aws-xray/LICENSE b/propagator/opentelemetry-propagator-aws-xray/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/propagator/opentelemetry-propagator-aws-xray/LICENSE +++ b/propagator/opentelemetry-propagator-aws-xray/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/propagator/opentelemetry-propagator-aws-xray/pyproject.toml b/propagator/opentelemetry-propagator-aws-xray/pyproject.toml index 4ece31fc53..6361de39a0 100644 --- a/propagator/opentelemetry-propagator-aws-xray/pyproject.toml +++ b/propagator/opentelemetry-propagator-aws-xray/pyproject.toml @@ -27,9 +27,6 @@ dependencies = [ "opentelemetry-api ~= 1.12", ] -[project.optional-dependencies] -test = [] - [project.entry-points.opentelemetry_propagator] xray = "opentelemetry.propagators.aws:AwsXRayPropagator" diff --git a/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt b/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt new file mode 100644 index 0000000000..b6b197bdcc --- /dev/null +++ b/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt @@ -0,0 +1,21 @@ +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +Deprecated==1.2.14 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +requests==2.31.0 +tomli==2.0.1 +typing_extensions==4.10.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e propagator/opentelemetry-propagator-aws-xray diff --git a/propagator/opentelemetry-propagator-ot-trace/pyproject.toml b/propagator/opentelemetry-propagator-ot-trace/pyproject.toml index 4b73034617..41f374ee1b 100644 --- a/propagator/opentelemetry-propagator-ot-trace/pyproject.toml +++ b/propagator/opentelemetry-propagator-ot-trace/pyproject.toml @@ -28,9 +28,6 @@ dependencies = [ "opentelemetry-sdk ~= 1.12", ] -[project.optional-dependencies] -test = [] - [project.entry-points.opentelemetry_propagator] ottrace = "opentelemetry.propagators.ot_trace:OTTracePropagator" diff --git a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py index c5c3496248..7924fe0b57 100644 --- a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py +++ b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py @@ -98,9 +98,9 @@ def extract( if not key.startswith(OT_BAGGAGE_PREFIX): continue - baggage[ - key[len(OT_BAGGAGE_PREFIX) :] - ] = _extract_first_element(getter.get(carrier, key)) + baggage[key[len(OT_BAGGAGE_PREFIX) :]] = ( + _extract_first_element(getter.get(carrier, key)) + ) for key, value in baggage.items(): context = set_baggage(key, value, context) diff --git a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/version.py b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/version.py index 2b23bc4994..ff4933b20b 100644 --- a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/version.py +++ b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt b/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt new file mode 100644 index 0000000000..69c1829a5c --- /dev/null +++ b/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt @@ -0,0 +1,16 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e propagator/opentelemetry-propagator-ot-trace diff --git a/resource/opentelemetry-resource-detector-azure/CHANGELOG.md b/resource/opentelemetry-resource-detector-azure/CHANGELOG.md new file mode 100644 index 0000000000..8954fc5359 --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/CHANGELOG.md @@ -0,0 +1,25 @@ +# 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/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +- Ignore vm detector if already in other rps + ([#2456](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2456)) + +## Version 0.1.4 (2024-04-05) + +- Fix windows tests/suppress instrumentation for urllib call + ([#2178](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2178)) + +## Version 0.1.3 (2024-01-25) + +- Change meta data service timeout to 200ms + ([#2387](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2387)) + +## Version 0.1.1 (2024-01-10) + +- Initial CHANGELOG.md entry diff --git a/resource/opentelemetry-resource-detector-azure/LICENSE b/resource/opentelemetry-resource-detector-azure/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/resource/opentelemetry-resource-detector-azure/LICENSE +++ b/resource/opentelemetry-resource-detector-azure/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/resource/opentelemetry-resource-detector-azure/pyproject.toml b/resource/opentelemetry-resource-detector-azure/pyproject.toml index ea4be96948..72260709f9 100644 --- a/resource/opentelemetry-resource-detector-azure/pyproject.toml +++ b/resource/opentelemetry-resource-detector-azure/pyproject.toml @@ -27,9 +27,6 @@ dependencies = [ "opentelemetry-sdk ~= 1.21", ] -[project.optional-dependencies] -test = [] - [project.entry-points.opentelemetry_resource_detector] azure_app_service = "opentelemetry.resource.detector.azure.app_service:AzureAppServiceResourceDetector" azure_vm = "opentelemetry.resource.detector.azure.vm:AzureVMResourceDetector" diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py new file mode 100644 index 0000000000..913b677c3e --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py @@ -0,0 +1,25 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=import-error + +from .app_service import AzureAppServiceResourceDetector +from .version import __version__ +from .vm import AzureVMResourceDetector + +__all__ = [ + "AzureAppServiceResourceDetector", + "AzureVMResourceDetector", + "__version__", +] diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py new file mode 100644 index 0000000000..dddc6632ac --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py @@ -0,0 +1,68 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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 opentelemetry.semconv.resource import ResourceAttributes + +# cSpell:disable + +# Azure Kubernetes + +_AKS_ARM_NAMESPACE_ID = "AKS_ARM_NAMESPACE_ID" + +# AppService + +_AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE = "azure.app.service.stamp" +_REGION_NAME = "REGION_NAME" +_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME" +_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME" +_WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID" +_WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME" +_WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP" +_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME" +_WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME" + +_APP_SERVICE_ATTRIBUTE_ENV_VARS = { + ResourceAttributes.CLOUD_REGION: _REGION_NAME, + ResourceAttributes.DEPLOYMENT_ENVIRONMENT: _WEBSITE_SLOT_NAME, + ResourceAttributes.HOST_ID: _WEBSITE_HOSTNAME, + ResourceAttributes.SERVICE_INSTANCE_ID: _WEBSITE_INSTANCE_ID, + _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE: _WEBSITE_HOME_STAMPNAME, +} + +# Functions + +_FUNCTIONS_WORKER_RUNTIME = "FUNCTIONS_WORKER_RUNTIME" + +# Vm + +_AZURE_VM_METADATA_ENDPOINT = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json" +_AZURE_VM_SCALE_SET_NAME_ATTRIBUTE = "azure.vm.scaleset.name" +_AZURE_VM_SKU_ATTRIBUTE = "azure.vm.sku" + +_EXPECTED_AZURE_AMS_ATTRIBUTES = [ + _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE, + _AZURE_VM_SKU_ATTRIBUTE, + ResourceAttributes.CLOUD_PLATFORM, + ResourceAttributes.CLOUD_PROVIDER, + ResourceAttributes.CLOUD_REGION, + ResourceAttributes.CLOUD_RESOURCE_ID, + ResourceAttributes.HOST_ID, + ResourceAttributes.HOST_NAME, + ResourceAttributes.HOST_TYPE, + ResourceAttributes.OS_TYPE, + ResourceAttributes.OS_VERSION, + ResourceAttributes.SERVICE_INSTANCE_ID, +] + +# cSpell:enable diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py new file mode 100644 index 0000000000..3f73613945 --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py @@ -0,0 +1,37 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from ._constants import ( + _AKS_ARM_NAMESPACE_ID, + _FUNCTIONS_WORKER_RUNTIME, + _WEBSITE_SITE_NAME, +) + + +def _is_on_aks() -> bool: + return os.environ.get(_AKS_ARM_NAMESPACE_ID) is not None + + +def _is_on_app_service() -> bool: + return os.environ.get(_WEBSITE_SITE_NAME) is not None + + +def _is_on_functions() -> bool: + return os.environ.get(_FUNCTIONS_WORKER_RUNTIME) is not None + + +def _can_ignore_vm_detect() -> bool: + return _is_on_aks() or _is_on_app_service() or _is_on_functions() diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py index 1e853acc57..613d8f9410 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py @@ -21,24 +21,12 @@ ResourceAttributes, ) -_AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE = "azure.app.service.stamp" -_REGION_NAME = "REGION_NAME" -_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME" -_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME" -_WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID" -_WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME" -_WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP" -_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME" -_WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME" - - -_APP_SERVICE_ATTRIBUTE_ENV_VARS = { - ResourceAttributes.CLOUD_REGION: _REGION_NAME, - ResourceAttributes.DEPLOYMENT_ENVIRONMENT: _WEBSITE_SLOT_NAME, - ResourceAttributes.HOST_ID: _WEBSITE_HOSTNAME, - ResourceAttributes.SERVICE_INSTANCE_ID: _WEBSITE_INSTANCE_ID, - _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE: _WEBSITE_HOME_STAMPNAME, -} +from ._constants import ( + _APP_SERVICE_ATTRIBUTE_ENV_VARS, + _WEBSITE_OWNER_NAME, + _WEBSITE_RESOURCE_GROUP, + _WEBSITE_SITE_NAME, +) class AzureAppServiceResourceDetector(ResourceDetector): @@ -47,19 +35,19 @@ def detect(self) -> Resource: website_site_name = environ.get(_WEBSITE_SITE_NAME) if website_site_name: attributes[ResourceAttributes.SERVICE_NAME] = website_site_name - attributes[ - ResourceAttributes.CLOUD_PROVIDER - ] = CloudProviderValues.AZURE.value - attributes[ - ResourceAttributes.CLOUD_PLATFORM - ] = CloudPlatformValues.AZURE_APP_SERVICE.value + attributes[ResourceAttributes.CLOUD_PROVIDER] = ( + CloudProviderValues.AZURE.value + ) + attributes[ResourceAttributes.CLOUD_PLATFORM] = ( + CloudPlatformValues.AZURE_APP_SERVICE.value + ) azure_resource_uri = _get_azure_resource_uri(website_site_name) if azure_resource_uri: - attributes[ - ResourceAttributes.CLOUD_RESOURCE_ID - ] = azure_resource_uri - for (key, env_var) in _APP_SERVICE_ATTRIBUTE_ENV_VARS.items(): + attributes[ResourceAttributes.CLOUD_RESOURCE_ID] = ( + azure_resource_uri + ) + for key, env_var in _APP_SERVICE_ATTRIBUTE_ENV_VARS.items(): value = environ.get(env_var) if value: attributes[key] = value diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/version.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/version.py index 97109f529b..f961659f70 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/version.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.1.2" +__version__ = "0.1.4" diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py index a4ba295ab9..2112282949 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py @@ -30,40 +30,31 @@ ResourceAttributes, ) -_AZURE_VM_METADATA_ENDPOINT = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json" -_AZURE_VM_SCALE_SET_NAME_ATTRIBUTE = "azure.vm.scaleset.name" -_AZURE_VM_SKU_ATTRIBUTE = "azure.vm.sku" -_logger = getLogger(__name__) - -EXPECTED_AZURE_AMS_ATTRIBUTES = [ +from ._constants import ( + _AZURE_VM_METADATA_ENDPOINT, _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE, _AZURE_VM_SKU_ATTRIBUTE, - ResourceAttributes.CLOUD_PLATFORM, - ResourceAttributes.CLOUD_PROVIDER, - ResourceAttributes.CLOUD_REGION, - ResourceAttributes.CLOUD_RESOURCE_ID, - ResourceAttributes.HOST_ID, - ResourceAttributes.HOST_NAME, - ResourceAttributes.HOST_TYPE, - ResourceAttributes.OS_TYPE, - ResourceAttributes.OS_VERSION, - ResourceAttributes.SERVICE_INSTANCE_ID, -] + _EXPECTED_AZURE_AMS_ATTRIBUTES, +) +from ._utils import _can_ignore_vm_detect + +_logger = getLogger(__name__) class AzureVMResourceDetector(ResourceDetector): # pylint: disable=no-self-use def detect(self) -> "Resource": attributes = {} - token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) - metadata_json = _get_azure_vm_metadata() - if not metadata_json: - return Resource(attributes) - for attribute_key in EXPECTED_AZURE_AMS_ATTRIBUTES: - attributes[attribute_key] = _get_attribute_from_metadata( - metadata_json, attribute_key - ) - detach(token) + if not _can_ignore_vm_detect(): + token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) + metadata_json = _get_azure_vm_metadata() + if not metadata_json: + return Resource(attributes) + for attribute_key in _EXPECTED_AZURE_AMS_ATTRIBUTES: + attributes[attribute_key] = _get_attribute_from_metadata( + metadata_json, attribute_key + ) + detach(token) return Resource(attributes) @@ -71,10 +62,8 @@ def _get_azure_vm_metadata(): request = Request(_AZURE_VM_METADATA_ENDPOINT) request.add_header("Metadata", "True") try: - # TODO: Changed to 4s to fit into OTel SDK's 5 second timeout. - # Lengthen or allow user input if issue is resolved. - # See https://github.com/open-telemetry/opentelemetry-python/issues/3644 - with urlopen(request, timeout=4) as response: + # VM metadata service should not take more than 200ms on success case + with urlopen(request, timeout=0.2) as response: return loads(response.read()) except URLError: # Not on Azure VM diff --git a/resource/opentelemetry-resource-detector-azure/tests/test_vm.py b/resource/opentelemetry-resource-detector-azure/tests/test_vm.py index 86aa373d3c..56d7d39104 100644 --- a/resource/opentelemetry-resource-detector-azure/tests/test_vm.py +++ b/resource/opentelemetry-resource-detector-azure/tests/test_vm.py @@ -378,3 +378,13 @@ def test_windows(self, mock_urlopen): attributes = AzureVMResourceDetector().detect().attributes for attribute_key, attribute_value in WINDOWS_ATTRIBUTES.items(): self.assertEqual(attributes[attribute_key], attribute_value) + + @patch("opentelemetry.resource.detector.azure.vm._can_ignore_vm_detect") + @patch("opentelemetry.resource.detector.azure.vm.urlopen") + def test_in_another_rp(self, mock_urlopen, detect_mock): + mock_urlopen.return_value.__enter__.return_value.read.return_value = ( + LINUX_JSON + ) + detect_mock.return_value = True + attributes = AzureVMResourceDetector().detect().attributes + self.assertEqual(attributes, {}) diff --git a/resource/opentelemetry-resource-detector-container/LICENSE b/resource/opentelemetry-resource-detector-container/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/resource/opentelemetry-resource-detector-container/LICENSE +++ b/resource/opentelemetry-resource-detector-container/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/resource/opentelemetry-resource-detector-container/pyproject.toml b/resource/opentelemetry-resource-detector-container/pyproject.toml index 9cb6685a2a..4ad1df12cd 100644 --- a/resource/opentelemetry-resource-detector-container/pyproject.toml +++ b/resource/opentelemetry-resource-detector-container/pyproject.toml @@ -27,9 +27,6 @@ dependencies = [ "opentelemetry-sdk ~= 1.12", ] -[project.optional-dependencies] -test = [] - [project.entry-points.opentelemetry_resource_detector] container = "opentelemetry.resource.detector.container:ContainerResourceDetector" diff --git a/resource/opentelemetry-resource-detector-container/src/opentelemetry/resource/detector/container/version.py b/resource/opentelemetry-resource-detector-container/src/opentelemetry/resource/detector/container/version.py index 2b23bc4994..ff4933b20b 100644 --- a/resource/opentelemetry-resource-detector-container/src/opentelemetry/resource/detector/container/version.py +++ b/resource/opentelemetry-resource-detector-container/src/opentelemetry/resource/detector/container/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev" diff --git a/resource/opentelemetry-resource-detector-container/test-requirements.txt b/resource/opentelemetry-resource-detector-container/test-requirements.txt new file mode 100644 index 0000000000..eee7aaa46d --- /dev/null +++ b/resource/opentelemetry-resource-detector-container/test-requirements.txt @@ -0,0 +1,16 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e resource/opentelemetry-resource-detector-container diff --git a/scripts/build.sh b/scripts/build.sh index fa490a6a35..247bb24b4e 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -8,13 +8,13 @@ set -ev # Get the latest versions of packaging tools python3 -m pip install --upgrade pip build setuptools wheel -BASEDIR=$(dirname $(readlink -f $(dirname $0))) +BASEDIR=$(dirname "$(readlink -f "$(dirname $0)")") DISTDIR=dist ( cd $BASEDIR mkdir -p $DISTDIR - rm -rf $DISTDIR/* + rm -rf ${DISTDIR:?}/* for d in exporter/*/ opentelemetry-instrumentation/ opentelemetry-contrib-instrumentations/ opentelemetry-distro/ instrumentation/*/ propagator/*/ resource/*/ sdk-extension/*/ util/*/ ; do ( diff --git a/scripts/build_a_package.sh b/scripts/build_a_package.sh index f3baa8a65a..333deccd80 100755 --- a/scripts/build_a_package.sh +++ b/scripts/build_a_package.sh @@ -22,7 +22,7 @@ set -ev if [ -z $GITHUB_REF ]; then echo 'Failed to run script, missing workflow env variable GITHUB_REF.' - exit -1 + exit 1 fi pkg_name_and_version=${GITHUB_REF#refs/tags/*} @@ -40,13 +40,13 @@ cd $basedir distdir=${basedir}/dist mkdir -p $distdir -rm -rf $distdir/* +rm -rf ${distdir:?}/* pyproject_toml_file_path=$(ls **/$pkg_name/pyproject.toml) if [ -z $pyproject_toml_file_path ]; then echo "Error! pyproject.toml not found for $pkg_name, can't build." - exit -1 + exit 1 fi directory_with_package=$(dirname $pyproject_toml_file_path) @@ -61,7 +61,7 @@ pkg_tar_gz_file=${pkg_name}-${pkg_version}.tar.gz if ! [ -f $pkg_tar_gz_file ]; then echo 'Error! Tag version does not match version built using latest package files.' - exit -1 + exit 1 fi # Build a wheel for the source distribution diff --git a/scripts/check_for_valid_readme.py b/scripts/check_for_valid_readme.py index 42446dd741..11b1fa81ac 100644 --- a/scripts/check_for_valid_readme.py +++ b/scripts/check_for_valid_readme.py @@ -1,4 +1,5 @@ """Test script to check given paths for valid README.rst files.""" + import argparse import sys from pathlib import Path diff --git a/scripts/coverage.sh b/scripts/coverage.sh index 4015c6884a..02ce1eed55 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -11,9 +11,6 @@ function cov { ${1} } -PYTHON_VERSION=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))') -PYTHON_VERSION_INFO=(${PYTHON_VERSION//./ }) - coverage erase cov instrumentation/opentelemetry-instrumentation-flask diff --git a/scripts/generate_instrumentation_readme.py b/scripts/generate_instrumentation_readme.py index 00045cd73c..79b8a5533d 100755 --- a/scripts/generate_instrumentation_readme.py +++ b/scripts/generate_instrumentation_readme.py @@ -23,8 +23,8 @@ _prefix = "opentelemetry-instrumentation-" header = """ -| Instrumentation | Supported Packages | Metrics support | -| --------------- | ------------------ | --------------- |""" +| Instrumentation | Supported Packages | Metrics support | Semconv status | +| --------------- | ------------------ | --------------- | -------------- |""" def main(): @@ -63,13 +63,17 @@ def main(): instruments = pkg_info["_instruments"] supports_metrics = pkg_info.get("_supports_metrics") + semconv_status = pkg_info.get("_semconv_status") if not instruments: instruments = (name,) + if not semconv_status: + semconv_status = "experimental" + metric_column = "Yes" if supports_metrics else "No" table.append( - f"| [{instrumentation}](./{instrumentation}) | {','.join(instruments)} | {metric_column}" + f"| [{instrumentation}](./{instrumentation}) | {','.join(instruments)} | {metric_column} | {semconv_status}" ) with open( diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE b/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE +++ b/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + 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. diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/pyproject.toml b/sdk-extension/opentelemetry-sdk-extension-aws/pyproject.toml index 252f9bb6f7..12b2b23ddc 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/pyproject.toml +++ b/sdk-extension/opentelemetry-sdk-extension-aws/pyproject.toml @@ -27,12 +27,16 @@ dependencies = [ "opentelemetry-sdk ~= 1.12", ] -[project.optional-dependencies] -test = [] - [project.entry-points.opentelemetry_id_generator] xray = "opentelemetry.sdk.extension.aws.trace.aws_xray_id_generator:AwsXRayIdGenerator" +[project.entry-points.opentelemetry_resource_detector] +aws_ec2 = "opentelemetry.sdk.extension.aws.resource.ec2:AwsEc2ResourceDetector" +aws_ecs = "opentelemetry.sdk.extension.aws.resource.ecs:AwsEcsResourceDetector" +aws_eks = "opentelemetry.sdk.extension.aws.resource.eks:AwsEksResourceDetector" +aws_elastic_beanstalk = "opentelemetry.sdk.extension.aws.resource.beanstalk:AwsBeanstalkResourceDetector" +aws_lambda = "opentelemetry.sdk.extension.aws.resource._lambda:AwsLambdaResourceDetector" + [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/sdk-extension/opentelemetry-sdk-extension-aws" diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt b/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt new file mode 100644 index 0000000000..e569ade322 --- /dev/null +++ b/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt @@ -0,0 +1,16 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e sdk-extension/opentelemetry-sdk-extension-aws diff --git a/tox.ini b/tox.ini index 45bf97bf8b..ed74e485cd 100644 --- a/tox.ini +++ b/tox.ini @@ -9,44 +9,54 @@ envlist = ; opentelemetry-resource-detector-container py3{8,9,10,11}-test-resource-detector-container pypy3-test-resource-detector-container + lint-resource-detector-container ; opentelemetry-sdk-extension-aws - py3{8,9,10,11}-test-sdkextension-aws - pypy3-test-sdkextension-aws + py3{8,9,10,11}-test-sdk-extension-aws + pypy3-test-sdk-extension-aws + lint-sdk-extension-aws ; opentelemetry-distro py3{8,9,10,11}-test-distro pypy3-test-distro + lint-distro ; opentelemetry-instrumentation py3{8,9,10,11}-test-opentelemetry-instrumentation pypy3-test-opentelemetry-instrumentation + lint-opentelemetry-instrumentation ; opentelemetry-instrumentation-aiohttp-client py3{8,9,10,11}-test-instrumentation-aiohttp-client pypy3-test-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client ; opentelemetry-instrumentation-aiohttp-server - py3{6,8,9,10,11}-test-instrumentation-aiohttp-server + py3{8,9,10,11}-test-instrumentation-aiohttp-server pypy3-test-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server ; opentelemetry-instrumentation-aiopg py3{8,9,10,11}-test-instrumentation-aiopg ; instrumentation-aiopg intentionally excluded from pypy3 + lint-instrumentation-aiopg ; opentelemetry-instrumentation-aws-lambda py3{8,9,10,11}-test-instrumentation-aws-lambda pypy3-test-instrumentation-aws-lambda + lint-instrumentation-aws-lambda ; opentelemetry-instrumentation-botocore py3{8,9,10,11}-test-instrumentation-botocore ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-botocore + lint-instrumentation-botocore ; opentelemetry-instrumentation-boto3sqs - py3{6,8,9,10,11}-test-instrumentation-boto3sqs + py3{8,9,10,11}-test-instrumentation-boto3sqs ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-boto3sqs + lint-instrumentation-boto3sqs ; opentelemetry-instrumentation-django ; Only officially supported Python versions are tested for each Django @@ -64,27 +74,27 @@ envlist = py3{10,11}-test-instrumentation-django-1 py3{10,11}-test-instrumentation-django-3 pypy3-test-instrumentation-django-{0,1} + lint-instrumentation-django ; opentelemetry-instrumentation-dbapi py3{8,9,10,11}-test-instrumentation-dbapi pypy3-test-instrumentation-dbapi + lint-instrumentation-dbapi ; opentelemetry-instrumentation-boto py3{8,9,10,11}-test-instrumentation-boto ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-boto + lint-instrumentation-boto ; opentelemetry-instrumentation-elasticsearch - ; FIXME: Elasticsearch >=7 causes CI workflow tests to hang, see open-telemetry/opentelemetry-python-contrib#620 ; The numbers at the end of the environment names ; below mean these dependencies are being used: - ; 0: elasticsearch-dsl>=2.0,<3.0 elasticsearch>=2.0,<3.0 - ; 1: elasticsearch-dsl>=5.0,<6.0 elasticsearch>=5.0,<6.0 - ; 2: elasticsearch-dsl>=6.0,<7.0 elasticsearch>=6.0,<7.0 - py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,2} - pypy3-test-instrumentation-elasticsearch-{0,2} - py3{8,9}-test-instrumentation-elasticsearch-1 - pypy3-test-instrumentation-elasticsearch-1 + ; 0: elasticsearch-dsl==6.4.0 elasticsearch==6.8.2 + ; 1: elasticsearch-dsl==7.4.1 elasticsearch==7.17.9 + py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,1} + pypy3-test-instrumentation-elasticsearch-{0,1} + lint-instrumentation-elasticsearch ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 @@ -96,10 +106,12 @@ envlist = py3{8,9}-test-instrumentation-falcon-0 py3{8,9,10,11}-test-instrumentation-falcon-{1,2} pypy3-test-instrumentation-falcon-{0,1,2} + lint-instrumentation-falcon ; opentelemetry-instrumentation-fastapi py3{8,9,10,11}-test-instrumentation-fastapi pypy3-test-instrumentation-fastapi + lint-instrumentation-fastapi ; opentelemetry-instrumentation-flask ; The numbers at the end of the environment names @@ -110,10 +122,12 @@ envlist = py3{8,9,10,11}-test-instrumentation-flask-{0,1} py3{8,9,10,11}-test-instrumentation-flask-{2} pypy3-test-instrumentation-flask-{0,1} + lint-instrumentation-flask ; opentelemetry-instrumentation-urllib py3{8,9,10,11}-test-instrumentation-urllib pypy3-test-instrumentation-urllib + lint-instrumentation-urllib ; opentelemetry-instrumentation-urllib3 ; The numbers at the end of the environment names @@ -122,46 +136,60 @@ envlist = ; 1: urllib3 >=2.0.0,<3.0.0 py3{8,9,10,11}-test-instrumentation-urllib3-{0,1} pypy3-test-instrumentation-urllib3-{0,1} + lint-instrumentation-urllib3 ; opentelemetry-instrumentation-requests py3{8,9,10,11}-test-instrumentation-requests ;pypy3-test-instrumentation-requests + lint-instrumentation-requests ; opentelemetry-instrumentation-starlette py3{8,9,10,11}-test-instrumentation-starlette pypy3-test-instrumentation-starlette + lint-instrumentation-starlette ; opentelemetry-instrumentation-jinja2 py3{8,9,10,11}-test-instrumentation-jinja2 pypy3-test-instrumentation-jinja2 + lint-instrumentation-jinja2 ; opentelemetry-instrumentation-logging py3{8,9,10,11}-test-instrumentation-logging pypy3-test-instrumentation-logging + lint-instrumentation-logging ; opentelemetry-exporter-richconsole py3{8,9,10,11}-test-exporter-richconsole pypy3-test-exporter-richconsole + lint-exporter-richconsole ; opentelemetry-exporter-prometheus-remote-write - py3{6,8,9,10,11}-test-exporter-prometheus-remote-write + py3{8,9,10,11}-test-exporter-prometheus-remote-write pypy3-test-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write ; opentelemetry-instrumentation-mysql py3{8,9,10,11}-test-instrumentation-mysql pypy3-test-instrumentation-mysql + lint-instrumentation-mysql ; opentelemetry-instrumentation-mysqlclient py3{8,9,10,11}-test-instrumentation-mysqlclient pypy3-test-instrumentation-mysqlclient + ; prerequisite: follow the instructions here + ; https://github.com/PyMySQL/mysqlclient#install + ; for your OS to install the required dependencies + lint-instrumentation-mysqlclient ; opentelemetry-instrumentation-psycopg2 py3{8,9,10,11}-test-instrumentation-psycopg2 ; ext-psycopg2 intentionally excluded from pypy3 + lint-instrumentation-psycopg2 ; opentelemetry-instrumentation-psycopg - py3{7,8,9,10,11}-test-instrumentation-psycopg + py3{8,9,10,11}-test-instrumentation-psycopg pypy3-test-instrumentation-psycopg + lint-instrumentation-psycopg ; opentelemetry-instrumentation-pymemcache ; The numbers at the end of the environment names @@ -173,38 +201,47 @@ envlist = ; 4: pymemcache ==4.0.0 py3{8,9,10,11}-test-instrumentation-pymemcache-{0,1,2,3,4} pypy3-test-instrumentation-pymemcache-{0,1,2,3,4} + lint-instrumentation-pymemcache ; opentelemetry-instrumentation-pymongo py3{8,9,10,11}-test-instrumentation-pymongo pypy3-test-instrumentation-pymongo + lint-instrumentation-pymongo ; opentelemetry-instrumentation-pymysql py3{8,9,10,11}-test-instrumentation-pymysql pypy3-test-instrumentation-pymysql + lint-instrumentation-pymysql ; opentelemetry-instrumentation-pyramid py3{8,9,10,11}-test-instrumentation-pyramid pypy3-test-instrumentation-pyramid + lint-instrumentation-pyramid ; opentelemetry-instrumentation-asgi py3{8,9,10,11}-test-instrumentation-asgi pypy3-test-instrumentation-asgi + lint-instrumentation-asgi ; opentelemetry-instrumentation-asyncpg py3{8,9,10,11}-test-instrumentation-asyncpg ; ext-asyncpg intentionally excluded from pypy3 + lint-instrumentation-asyncpg ; opentelemetry-instrumentation-sqlite3 py3{8,9,10,11}-test-instrumentation-sqlite3 pypy3-test-instrumentation-sqlite3 + lint-instrumentation-sqlite3 ; opentelemetry-instrumentation-wsgi py3{8,9,10,11}-test-instrumentation-wsgi pypy3-test-instrumentation-wsgi + lint-instrumentation-wsgi ; opentelemetry-instrumentation-grpc py3{8,9,10,11}-test-instrumentation-grpc pypy3-test-instrumentation-grpc + lint-instrumentation-grpc ; opentelemetry-instrumentation-sqlalchemy ; The numbers at the end of the environment names @@ -213,37 +250,55 @@ envlist = ; 1: sqlalchemy~=1.4 aiosqlite py3{8,9,10,11}-test-instrumentation-sqlalchemy-{1} pypy3-test-instrumentation-sqlalchemy-{0,1} + lint-instrumentation-sqlalchemy ; opentelemetry-instrumentation-redis py3{8,9,10,11}-test-instrumentation-redis pypy3-test-instrumentation-redis + lint-instrumentation-redis ; opentelemetry-instrumentation-remoulade py3{8,9,10,11}-test-instrumentation-remoulade ; instrumentation-remoulade intentionally excluded from pypy3 + lint-instrumentation-remoulade ; opentelemetry-instrumentation-celery py3{8,9,10,11}-test-instrumentation-celery pypy3-test-instrumentation-celery + lint-instrumentation-celery ; opentelemetry-instrumentation-sklearn py3{8}-test-instrumentation-sklearn + lint-instrumentation-sklearn ; opentelemetry-instrumentation-system-metrics - py3{6,8,9,10,11}-test-instrumentation-system-metrics + py3{8,9,10,11}-test-instrumentation-system-metrics pypy3-test-instrumentation-system-metrics + lint-instrumentation-system-metrics + + ; opentelemetry-instrumentation-threading + py3{8,9,10,11}-test-instrumentation-threading + pypy3-test-instrumentation-threading + lint-instrumentation-threading ; opentelemetry-instrumentation-tornado py3{8,9,10,11}-test-instrumentation-tornado pypy3-test-instrumentation-tornado + lint-instrumentation-tornado ; opentelemetry-instrumentation-tortoiseorm py3{8,9,10,11}-test-instrumentation-tortoiseorm pypy3-test-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm ; opentelemetry-instrumentation-httpx + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: httpx>=0.18.0,<0.19.0 respx~=0.17.0 + ; 1: httpx>=0.19.0 respx~=0.20.1 py3{8,9,10,11}-test-instrumentation-httpx-{0,1} pypy3-test-instrumentation-httpx-{0,1} + lint-instrumentation-httpx ; opentelemetry-util-http py3{8,9,10,11}-test-util-http @@ -252,40 +307,58 @@ envlist = ; opentelemetry-propagator-aws-xray py3{8,9,10,11}-test-propagator-aws-xray pypy3-test-propagator-aws-xray + lint-propagator-aws-xray ; opentelemetry-propagator-ot-trace py3{8,9,10,11}-test-propagator-ot-trace pypy3-test-propagator-ot-trace + lint-propagator-ot-trace ; opentelemetry-instrumentation-sio-pika + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: pika>=0.12.0,<1.0.0 + ; 1: pika>=1.0.0 py3{8,9,10,11}-test-instrumentation-sio-pika-{0,1} pypy3-test-instrumentation-sio-pika-{0,1} + lint-instrumentation-sio-pika ; opentelemetry-instrumentation-aio-pika ; The numbers at the end of the environment names ; below mean these dependencies are being used: - ; 0: aio_pika~=7.2.0 - ; 1: aio_pika>=8.0.0,<9.0.0 - ; 2: aio_pika>=9.0.0,<10.0.0 - py3{8,9,10,11}-test-instrumentation-aio-pika-{0,1,2} - pypy3-test-instrumentation-aio-pika-{0,1,2} + ; 0: aio_pika==7.2.0 + ; 1: aio_pika==8.3.0 + ; 2: aio_pika==9.0.5 + ; 3: aio_pika==9.4.1 + py3{8,9,10,11}-test-instrumentation-aio-pika-{0,1,2,3} + pypy3-test-instrumentation-aio-pika-{0,1,2,3} + lint-instrumentation-aio-pika ; opentelemetry-instrumentation-kafka-python py3{8,9,10,11}-test-instrumentation-kafka-python pypy3-test-instrumentation-kafka-python + lint-instrumentation-kafka-python ; opentelemetry-instrumentation-confluent-kafka py3{8,9,10,11}-test-instrumentation-confluent-kafka pypy3-test-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka ; opentelemetry-instrumentation-asyncio py3{8,9,10,11}-test-instrumentation-asyncio + lint-instrumentation-asyncio ; opentelemetry-instrumentation-cassandra py3{8,9,10,11}-test-instrumentation-cassandra pypy3-test-instrumentation-cassandra + lint-instrumentation-cassandra + + ; opentelemetry-processor-baggage + py3{8,9,10,11}-test-processor-baggage + pypy3-test-processor-baggage + ; requires snappy headers to be available on the system + lint-processor-baggage - lint spellcheck docker-tests docs @@ -295,13 +368,12 @@ envlist = [testenv] deps = -c dev-requirements.txt + lint: -r dev-requirements.txt test: pytest test: pytest-benchmark coverage: pytest coverage: pytest-cov grpc: pytest-asyncio - sio-pika-0: pika>=0.12.0,<1.0.0 - sio-pika-1: pika>=1.0.0 ; FIXME: add coverage testing ; FIXME: add mypy testing @@ -313,64 +385,150 @@ setenv = CORE_REPO=git+https://github.com/open-telemetry/opentelemetry-python.git@{env:CORE_REPO_SHA} commands_pre = -; Install without -e to test the actual installation - py3{8,9,10,11}: python -m pip install -U pip setuptools wheel -; Install common packages for all the tests. These are not needed in all the -; cases but it saves a lot of boilerplate in this file. - test: pip install opentelemetry-api[test]@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api - test: pip install opentelemetry-semantic-conventions[test]@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions - test: pip install opentelemetry-sdk[test]@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk - test: pip install opentelemetry-test-utils[test]@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils - test: pip install {toxinidir}/opentelemetry-instrumentation - - distro: pip install {toxinidir}/opentelemetry-distro - + opentelemetry-instrumentation: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + opentelemetry-instrumentation: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + opentelemetry-instrumentation: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + opentelemetry-instrumentation: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + opentelemetry-instrumentation: pip install -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt + + distro: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + distro: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + distro: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + distro: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + distro: pip install -r {toxinidir}/opentelemetry-distro/test-requirements.txt + + asgi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asgi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asgi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asgi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils asgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt - celery: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] - - sio-pika-{0,1}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] - + celery: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + celery: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + celery: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + celery: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + py3{8,9}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt + py3{10,11}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + pypy3-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + lint-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + + sio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sio-pika: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt + sio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt + lint-instrumentation-sio-pika: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt + + aio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aio-pika: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk aio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-0.txt aio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt aio-pika-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - - kafka-python: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] - - confluent-kafka: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] - - grpc: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] - + aio-pika-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt + lint-instrumentation-aio-pika: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt + + kafka-python: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + kafka-python: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + kafka-python: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + kafka-python: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt + + confluent-kafka: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + confluent-kafka: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + confluent-kafka: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + confluent-kafka: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + confluent-kafka: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt + + grpc: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + grpc: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + grpc: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + grpc: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + grpc: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt + + wsgi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + wsgi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + wsgi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + wsgi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils wsgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt - asyncpg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] - - aws-lambda: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] - - boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] - - boto3sqs: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] - + asyncpg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asyncpg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asyncpg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asyncpg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + asyncpg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt + + aws-lambda: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aws-lambda: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aws-lambda: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aws-lambda: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + aws-lambda: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt + + boto: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + boto: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + boto: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + boto: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + boto: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt + + boto3sqs: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + boto3sqs: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + boto3sqs: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + boto3sqs: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + boto3sqs: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt + + falcon: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + falcon: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + falcon: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + falcon: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils falcon-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-0.txt falcon-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt falcon-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt + lint-instrumentation-falcon: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt + flask: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + flask: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + flask: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + flask: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils flask-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-0.txt flask-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt flask-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt + lint-instrumentation-flask: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt + urllib: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + urllib: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + urllib: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + urllib: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils urllib: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt + urllib3: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + urllib3: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + urllib3: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + urllib3: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils urllib3-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-0.txt urllib3-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt - - botocore: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - - cassandra: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] - + lint-instrumentation-urllib3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt + + botocore: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + botocore: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + botocore: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + botocore: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + botocore: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt + + cassandra: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + cassandra: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + cassandra: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + cassandra: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + cassandra: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt + + dbapi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + dbapi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + dbapi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + dbapi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils dbapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt + django: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + django: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + django: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + django: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils py3{8,9}-test-instrumentation-django-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt py3{8,9}-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt py3{8,9}-test-instrumentation-django-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt @@ -378,149 +536,639 @@ commands_pre = py3{10,11}-test-instrumentation-django-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt pypy3-test-instrumentation-django-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt pypy3-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt + lint-instrumentation-django: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt + fastapi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + fastapi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + fastapi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + fastapi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils fastapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt - mysql: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] + mysql: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + mysql: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + mysql: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + mysql: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + mysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt + mysqlclient: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + mysqlclient: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + mysqlclient: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + mysqlclient: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils mysqlclient: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt + pymemcache: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymemcache: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymemcache: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymemcache: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pymemcache-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-0.txt pymemcache-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-1.txt pymemcache-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.txt pymemcache-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.txt pymemcache-4: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt - - pymongo: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] - - psycopg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg[test] - - psycopg2: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] - - pymysql: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] - + lint-instrumentation-pymemcache: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt + + pymongo: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymongo: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymongo: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymongo: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + pymongo: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt + + psycopg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + psycopg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + psycopg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + psycopg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + py3{8,9}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt + py3{10,11}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + pypy3-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + lint-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + + psycopg2: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + psycopg2: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + psycopg2: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + psycopg2: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + psycopg2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt + + pymysql: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymysql: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymysql: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymysql: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + pymysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt + + pyramid: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pyramid: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pyramid: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pyramid: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pyramid: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt - sqlite3: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] - - redis: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] - - remoulade: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] - + sqlite3: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sqlite3: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sqlite3: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sqlite3: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + sqlite3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt + + redis: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + redis: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + redis: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + redis: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + redis: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt + + remoulade: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + remoulade: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + remoulade: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + remoulade: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + remoulade: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt + + requests: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + requests: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + requests: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + requests: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils requests: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt + starlette: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + starlette: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + starlette: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + starlette: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils starlette: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt - system-metrics: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] - + system-metrics: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + system-metrics: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + system-metrics: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + system-metrics: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + system-metrics: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt + + threading: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + threading: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + threading: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + threading: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + threading: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt + + tornado: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + tornado: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + tornado: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + tornado: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils tornado: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt - tortoiseorm: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] - - jinja2: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] - - logging: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] - - aio-pika-{0,1,2}: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - + tortoiseorm: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + tortoiseorm: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + tortoiseorm: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + tortoiseorm: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + tortoiseorm: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt + + jinja2: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + jinja2: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + jinja2: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + jinja2: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + jinja2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt + + logging: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + logging: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + logging: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + logging: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + logging: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt + + aiohttp-client: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiohttp-client: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiohttp-client: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiohttp-client: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiohttp-client: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt + aiohttp-server: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiohttp-server: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiohttp-server: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiohttp-server: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiohttp-server: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt + aiopg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiopg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiopg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiopg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt - richconsole: pip install flaky {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] - - prometheus: pip install {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write[test] - - sklearn: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] - + richconsole: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + richconsole: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + richconsole: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + richconsole: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + richconsole: pip install -r {toxinidir}/exporter/opentelemetry-exporter-richconsole/test-requirements.txt + + prometheus: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + prometheus: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + prometheus: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + prometheus: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + prometheus: pip install -r {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt + + sklearn: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sklearn: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sklearn: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sklearn: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + sklearn: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt + + sqlalchemy: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sqlalchemy: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sqlalchemy: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sqlalchemy: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + lint-instrumentation-sqlalchemy: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + elasticsearch: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + elasticsearch: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + elasticsearch: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + elasticsearch: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils elasticsearch-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt elasticsearch-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt - elasticsearch-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt + lint-instrumentation-elasticsearch: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt + asyncio: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asyncio: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asyncio: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asyncio: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils asyncio: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt - ; The numbers at the end of the environment names - ; below mean these dependencies are being used: - ; 0: httpx>=0.18.0,<0.19.0 respx~=0.17.0 - ; 1: httpx>=0.19.0 respx~=0.20.1 + httpx: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + httpx: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + httpx: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + httpx: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils httpx-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-0.txt httpx-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt - - sdkextension-aws: pip install {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] - - resource-detector-container: pip install {toxinidir}/resource/opentelemetry-resource-detector-container[test] + lint-instrumentation-httpx: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt + + sdk-extension-aws: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sdk-extension-aws: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sdk-extension-aws: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sdk-extension-aws: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + sdk-extension-aws: pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt + + resource-detector-container: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + resource-detector-container: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + resource-detector-container: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + resource-detector-container: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + resource-detector-container: pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/test-requirements.txt + + propagator-ot-trace: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + propagator-ot-trace: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + propagator-ot-trace: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + propagator-ot-trace: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + propagator-ot-trace: pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt + + propagator-aws-xray: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + propagator-aws-xray: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + propagator-aws-xray: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + propagator-aws-xray: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils + propagator-aws-xray: pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt + + processor-baggage: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + processor-baggage: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + processor-baggage: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + processor-baggage: pip install -r {toxinidir}/processor/opentelemetry-processor-baggage/test-requirements.txt http: pip install {toxinidir}/util/opentelemetry-util-http -; In order to get a health coverage report, - propagator-ot-trace: pip install {toxinidir}/propagator/opentelemetry-propagator-ot-trace[test] - - propagator-aws-xray: pip install requests {toxinidir}/propagator/opentelemetry-propagator-aws-xray[test] +; In order to get a health coverage report, ; we have to install packages in editable mode. coverage: python {toxinidir}/scripts/eachdist.py install --editable commands = test-distro: pytest {toxinidir}/opentelemetry-distro/tests {posargs} + lint-distro: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/opentelemetry-distro + lint-distro: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/opentelemetry-distro + lint-distro: flake8 --config {toxinidir}/.flake8 {toxinidir}/opentelemetry-distro + lint-distro: pylint {toxinidir}/opentelemetry-distro/src/opentelemetry + lint-distro: pylint {toxinidir}/opentelemetry-distro/tests + test-opentelemetry-instrumentation: pytest {toxinidir}/opentelemetry-instrumentation/tests {posargs} + lint-opentelemetry-instrumentation: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: flake8 --config {toxinidir}/.flake8 {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: pylint {toxinidir}/opentelemetry-instrumentation/src/opentelemetry + lint-opentelemetry-instrumentation: pylint {toxinidir}/opentelemetry-instrumentation/tests + test-instrumentation-aiohttp-client: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests {posargs} + lint-instrumentation-aiohttp-client: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry + lint-instrumentation-aiohttp-client: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests + test-instrumentation-aiohttp-server: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests {posargs} + lint-instrumentation-aiohttp-server: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry + lint-instrumentation-aiohttp-server: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests + test-instrumentation-aiopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/tests {posargs} + lint-instrumentation-aiopg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry + lint-instrumentation-aiopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/tests + test-instrumentation-asgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/tests {posargs} + lint-instrumentation-asgi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry + lint-instrumentation-asgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/tests + test-instrumentation-asyncpg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/tests {posargs} + lint-instrumentation-asyncpg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry + lint-instrumentation-asyncpg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/tests + test-instrumentation-aws-lambda: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/tests {posargs} + lint-instrumentation-aws-lambda: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry + lint-instrumentation-aws-lambda: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/tests + test-instrumentation-boto: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/tests {posargs} + lint-instrumentation-boto: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry + lint-instrumentation-boto: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/tests + test-instrumentation-botocore: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/tests {posargs} + lint-instrumentation-botocore: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry + lint-instrumentation-botocore: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/tests + test-instrumentation-boto3sqs: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/tests {posargs} + lint-instrumentation-boto3sqs: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry + lint-instrumentation-boto3sqs: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/tests + test-instrumentation-cassandra: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/tests {posargs} + lint-instrumentation-cassandra: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry + lint-instrumentation-cassandra: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/tests + test-instrumentation-celery: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/tests {posargs} + lint-instrumentation-celery: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry + lint-instrumentation-celery: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/tests + test-instrumentation-dbapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/tests {posargs} + lint-instrumentation-dbapi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry + lint-instrumentation-dbapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/tests + test-instrumentation-django: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-django/tests {posargs} + lint-instrumentation-django: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry + lint-instrumentation-django: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-django/tests + test-instrumentation-elasticsearch: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/tests {posargs} + lint-instrumentation-elasticsearch: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry + lint-instrumentation-elasticsearch: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/tests + test-instrumentation-falcon: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/tests {posargs} + lint-instrumentation-falcon: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry + lint-instrumentation-falcon: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/tests + test-instrumentation-fastapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/tests {posargs} + lint-instrumentation-fastapi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry + lint-instrumentation-fastapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/tests + test-instrumentation-flask: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/tests {posargs} + lint-instrumentation-flask: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry + lint-instrumentation-flask: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/tests + test-instrumentation-urllib: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/tests {posargs} + lint-instrumentation-urllib: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry + lint-instrumentation-urllib: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/tests + test-instrumentation-urllib3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/tests {posargs} + lint-instrumentation-urllib3: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry + lint-instrumentation-urllib3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/tests + test-instrumentation-grpc: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/tests {posargs} + lint-instrumentation-grpc: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry + lint-instrumentation-grpc: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/tests + test-instrumentation-jinja2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/tests {posargs} + lint-instrumentation-jinja2: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry + lint-instrumentation-jinja2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/tests + test-instrumentation-kafka-python: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/tests {posargs} + lint-instrumentation-kafka-python: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry + lint-instrumentation-kafka-python: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/tests + test-instrumentation-confluent-kafka: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/tests {posargs} + lint-instrumentation-confluent-kafka: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry + lint-instrumentation-confluent-kafka: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/tests + test-instrumentation-logging: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/tests {posargs} + lint-instrumentation-logging: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry + lint-instrumentation-logging: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/tests + test-instrumentation-mysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/tests {posargs} + lint-instrumentation-mysql: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry + lint-instrumentation-mysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/tests + test-instrumentation-mysqlclient: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/tests {posargs} + lint-instrumentation-mysqlclient: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry + lint-instrumentation-mysqlclient: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/tests + test-instrumentation-sio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/tests {posargs} + lint-instrumentation-sio-pika: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry + lint-instrumentation-sio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/tests + test-instrumentation-aio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/tests {posargs} + lint-instrumentation-aio-pika: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry + lint-instrumentation-aio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/tests + test-instrumentation-psycopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/tests {posargs} + lint-instrumentation-psycopg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry + lint-instrumentation-psycopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/tests + test-instrumentation-psycopg2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/tests {posargs} + lint-instrumentation-psycopg2: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry + lint-instrumentation-psycopg2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/tests + test-instrumentation-pymemcache: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/tests {posargs} + lint-instrumentation-pymemcache: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry + lint-instrumentation-pymemcache: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/tests + test-instrumentation-pymongo: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/tests {posargs} + lint-instrumentation-pymongo: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry + lint-instrumentation-pymongo: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/tests + test-instrumentation-pymysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/tests {posargs} + lint-instrumentation-pymysql: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry + lint-instrumentation-pymysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/tests + test-instrumentation-pyramid: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/tests {posargs} + lint-instrumentation-pyramid: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry + lint-instrumentation-pyramid: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/tests + test-instrumentation-redis: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/tests {posargs} + lint-instrumentation-redis: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry + lint-instrumentation-redis: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/tests + test-instrumentation-remoulade: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/tests {posargs} + lint-instrumentation-remoulade: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry + lint-instrumentation-remoulade: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/tests + test-instrumentation-requests: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/tests {posargs} + lint-instrumentation-requests: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry + lint-instrumentation-requests: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/tests + test-instrumentation-sklearn: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/tests {posargs} + lint-instrumentation-sklearn: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry + lint-instrumentation-sklearn: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/tests + test-instrumentation-sqlalchemy: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests {posargs} + lint-instrumentation-sqlalchemy: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry + lint-instrumentation-sqlalchemy: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests + test-instrumentation-sqlite3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/tests {posargs} + lint-instrumentation-sqlite3: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry + lint-instrumentation-sqlite3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/tests + test-instrumentation-starlette: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/tests {posargs} + lint-instrumentation-starlette: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry + lint-instrumentation-starlette: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/tests + test-instrumentation-system-metrics: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/tests {posargs} + lint-instrumentation-system-metrics: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry + lint-instrumentation-system-metrics: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/tests + + test-instrumentation-threading: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/tests {posargs} + lint-instrumentation-threading: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry + lint-instrumentation-threading: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/tests + test-instrumentation-tornado: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/tests {posargs} + lint-instrumentation-tornado: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry + lint-instrumentation-tornado: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/tests + test-instrumentation-tortoiseorm: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/tests {posargs} + lint-instrumentation-tortoiseorm: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry + lint-instrumentation-tortoiseorm: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/tests + test-instrumentation-wsgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/tests {posargs} + lint-instrumentation-wsgi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry + lint-instrumentation-wsgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/tests + test-instrumentation-httpx: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/tests {posargs} + lint-instrumentation-httpx: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry + lint-instrumentation-httpx: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/tests + test-instrumentation-asyncio: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/tests {posargs} + lint-instrumentation-asyncio: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry + lint-instrumentation-asyncio: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/tests + test-util-http: pytest {toxinidir}/util/opentelemetry-util-http/tests {posargs} - test-sdkextension-aws: pytest {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests {posargs} + + test-sdk-extension-aws: pytest {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests {posargs} + lint-sdk-extension-aws: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: flake8 --config {toxinidir}/.flake8 {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: pylint {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry + lint-sdk-extension-aws: pylint {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests + test-resource-detector-container: pytest {toxinidir}/resource/opentelemetry-resource-detector-container/tests {posargs} - test-propagator-aws: pytest {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests {posargs} + lint-resource-detector-container: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: flake8 --config {toxinidir}/.flake8 {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: pylint {toxinidir}/resource/opentelemetry-resource-detector-container/src/opentelemetry + lint-resource-detector-container: pylint {toxinidir}/resource/opentelemetry-resource-detector-container/tests + + test-processor-baggage: pytest {toxinidir}/processor/opentelemetry-processor-baggage/tests {posargs} + lint-processor-baggage: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: flake8 --config {toxinidir}/.flake8 {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: pylint {toxinidir}/processor/opentelemetry-processor-baggage/src/opentelemetry + lint-processor-baggage: pylint {toxinidir}/processor/opentelemetry-processor-baggage/tests + + test-propagator-aws-xray: pytest {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests {posargs} + lint-propagator-aws-xray: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: flake8 --config {toxinidir}/.flake8 {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: pylint {toxinidir}/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry + lint-propagator-aws-xray: pylint {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests + test-propagator-ot-trace: pytest {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests {posargs} + lint-propagator-ot-trace: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: flake8 --config {toxinidir}/.flake8 {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: pylint {toxinidir}/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry + lint-propagator-ot-trace: pylint {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests + test-exporter-richconsole: pytest {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests {posargs} + lint-exporter-richconsole: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: flake8 --config {toxinidir}/.flake8 {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: pylint {toxinidir}/exporter/opentelemetry-exporter-richconsole/src/opentelemetry + lint-exporter-richconsole: pylint {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests + test-exporter-prometheus-remote-write: pytest {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests {posargs} + lint-exporter-prometheus-remote-write: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: flake8 --config {toxinidir}/.flake8 {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: pylint {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry + lint-exporter-prometheus-remote-write: pylint {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests + coverage: {toxinidir}/scripts/coverage.sh [testenv:docs] @@ -550,79 +1198,6 @@ deps = commands = codespell -[testenv:lint] -basepython: python3 -recreate = True -deps = - -r dev-requirements.txt - -commands_pre = - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils - python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test] - python -m pip install -e {toxinidir}/opentelemetry-instrumentation[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - ; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] - # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install - # for your OS to install the required dependencies - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt - python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] - # requires snappy headers to be available on the system - python -m pip install -e {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] - python -m pip install -e {toxinidir}/resource/opentelemetry-resource-detector-container[test] - python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-aws-xray[test] - python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-ot-trace[test] - python -m pip install -e {toxinidir}/opentelemetry-distro[test] - -commands = - python scripts/eachdist.py lint --check-only - [testenv:docker-tests] basepython: python3 deps = @@ -630,7 +1205,7 @@ deps = amqp==5.2.0 asgiref==3.7.2 async-timeout==4.0.3 - asyncpg==0.27.0 + asyncpg==0.29.0 attrs==23.2.0 bcrypt==4.1.2 billiard==4.2.0 @@ -678,6 +1253,7 @@ deps = pymongo==4.6.2 PyMySQL==0.10.1 PyNaCl==1.5.0 + # prerequisite: install unixodbc pyodbc==4.0.39 pyrsistent==0.20.0 pytest==8.0.2 @@ -686,7 +1262,7 @@ deps = python-dotenv==0.21.1 pytz==2024.1 PyYAML==5.3.1 - redis==4.6.0 + redis==5.0.1 remoulade==3.2.0 requests==2.25.0 six==1.16.0 diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index 246845ef0f..300c85721d 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -218,7 +218,7 @@ def sanitize_method(method: Optional[str]) -> Optional[str]: ] ): return method - return "UNKNOWN" + return "_OTHER" def get_custom_headers(env_var: str) -> list[str]: @@ -245,3 +245,10 @@ def _parse_duration_attrs(req_attrs): for key in _duration_attrs.intersection(req_attrs.keys()) } return duration_attrs + + +def _parse_url_query(url: str): + parsed_url = urlparse(url) + path = parsed_url.path + query_params = parsed_url.query + return path, query_params diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/version.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/version.py index 2b23bc4994..ff4933b20b 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/version.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.45b0.dev" +__version__ = "0.46b0.dev"