diff --git a/.github/workflows/instrumentations_0.yml b/.github/workflows/instrumentations_0.yml index 5505fce008..256d160640 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: diff --git a/.github/workflows/instrumentations_1.yml b/.github/workflows/instrumentations_1.yml index 0640c056a6..59db21529a 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: @@ -25,13 +25,13 @@ jobs: python-version: [py38, py39, py310, py311, pypy3] package: - "urllib" - - "urllib3v" + - "urllib3" - "wsgi" - "distro" - "richconsole" - "psycopg" - "prometheus-remote-write" - - "sdkextension-aws" + - "sdk-extension-aws" - "propagator-aws-xray" - "propagator-ot-trace" - "resource-detector-container" 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..10c648e517 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: a1253585f66d63e7c05a19f070f3bfe0ab6460c1 + CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 jobs: misc: 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 dbb5b07622..2b2ff4c176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,74 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- `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))) + + +### 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)) + +### 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-threading` Initial release for threading + ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) + +### 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)) +### 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-threading` Initial release for threading + ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) + +## 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 + ([#1756](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1756)) +- `opentelemetry-instrumentation-flask` Add importlib metadata default for deprecation warning flask version + ([#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 support for 3.7 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c76634db7..0c18392bc7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,26 @@ on how to become a [**Member**](https://github.com/open-telemetry/community/blob [**Approver**](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver) and [**Maintainer**](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer). -## Find a Buddy and get Started Quickly! +## Index + +* [Find a Buddy and get Started Quickly](#find-a-buddy-and-get-started-quickly) +* [Development](#development) + * [Troubleshooting](#troubleshooting) + * [Benchmarks](#benchmarks) +* [Pull requests](#pull-requests) + * [How to Send Pull Requests](#how-to-send-pull-requests) + * [How to Receive Comments](#how-to-receive-comments) + * [How to Get PRs Reviewed](#how-to-get-prs-reviewed) + * [How to Get PRs Merged](#how-to-get-prs-merged) +* [Design Choices](#design-choices) + * [Focus on Capabilities, Not Structure Compliance](#focus-on-capabilities-not-structure-compliance) +* [Running Tests Locally](#running-tests-locally) + * [Testing against a different Core repo branch/commit](#testing-against-a-different-core-repo-branchcommit) +* [Style Guide](#style-guide) +* [Guideline for instrumentations](#guideline-for-instrumentations) +* [Expectations from contributors](#expectations-from-contributors) + +## Find a Buddy and get Started Quickly If you are looking for someone to help you find a starting point and be a resource for your first contribution, join our Slack and find a buddy! @@ -31,8 +50,8 @@ This project uses [tox](https://tox.readthedocs.io) to automate some aspects of development, including testing against multiple Python versions. To install `tox`, run: -```console -$ pip install tox +```sh +pip install tox ``` You can run `tox` with the following arguments: @@ -57,7 +76,7 @@ for more detail on available tox commands. ### Troubleshooting -- Some packages may require additional system wide dependencies to be installed. For example, you may need to install `libpq-dev` to run the postgresql client libraries instrumentation tests. or `libsnappy-dev` to run the prometheus exporter tests. If you encounter a build error, please check the installation instructions for the package you are trying to run tests for. +> Some packages may require additional system wide dependencies to be installed. For example, you may need to install `libpq-dev` to run the postgresql client libraries instrumentation tests. or `libsnappy-dev` to run the prometheus exporter tests. If you encounter a build error, please check the installation instructions for the package you are trying to run tests for. ### Benchmarks @@ -94,13 +113,13 @@ pull requests (PRs). To create a new PR, fork the project in GitHub and clone the upstream repo: ```sh -$ git clone https://github.com/open-telemetry/opentelemetry-python-contrib.git +git clone https://github.com/open-telemetry/opentelemetry-python-contrib.git ``` Add your fork as an origin: ```sh -$ git remote add fork https://github.com/YOUR_GITHUB_USERNAME/opentelemetry-python-contrib.git +git remote add fork https://github.com/YOUR_GITHUB_USERNAME/opentelemetry-python-contrib.git ``` Run tests: @@ -114,10 +133,10 @@ $ tox # execute in the root of the repository Check out a new branch, make modifications and push the branch to your fork: ```sh -$ git checkout -b feature +git checkout -b feature # edit files -$ git commit -$ git push fork feature +git commit +git push fork feature ``` Open a pull request against the main `opentelemetry-python-contrib` repo. @@ -142,6 +161,7 @@ If you are not getting reviews, please contact the respective owners directly. ### How to Get PRs Merged A PR is considered to be **ready to merge** when: + * It has received two approvals from [Approvers](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver) / [Maintainers](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer) (at different companies). @@ -186,8 +206,7 @@ Some of the tox targets install packages from the [OpenTelemetry Python Core Rep CORE_REPO_SHA=c49ad57bfe35cfc69bfa863d74058ca9bec55fc3 tox -The continuation integration overrides that environment variable with as per the configuration [here](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/.github/workflows/test.yml#L9). - +The continuation integration overrides that environment variable with as per the configuration [here](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/2518a4ac07cb62ad6587dd8f6cbb5f8663a7e179/.github/workflows/test.yml#L9). ## Style Guide @@ -203,27 +222,25 @@ Below is a checklist of things to be mindful of when implementing a new instrume - Follow semantic conventions - The instrumentation should follow the semantic conventions defined [here](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/semantic-conventions.md) -- Extends from [BaseInstrumentor](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py#L26) +- Extends from [BaseInstrumentor](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/2518a4ac07cb62ad6587dd8f6cbb5f8663a7e179/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py#L35) - Supports auto-instrumentation - - Add an entry point (ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/f045c43affff6ff1af8fa2f7514a4fdaca97dacf/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml#L44) + - Add an entry point (ex. ) - Run `python scripts/generate_instrumentation_bootstrap.py` after adding a new instrumentation package. - Functionality that is common amongst other instrumentation and can be abstracted [here](https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation) - Request/response [hooks](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/408) for http instrumentations - `suppress_instrumentation` functionality - - ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/3ec77360cb20482b08b30312a6bedc8b946e3fa1/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py#L111 + - ex. - Suppress propagation functionality - https://github.com/open-telemetry/opentelemetry-python-contrib/issues/344 for more context - `exclude_urls` functionality - - ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/0fcb60d2ad139f78a52edd85b1cc4e32f2e962d0/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py#L91 + - ex. - `url_filter` functionality - - ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/0fcb60d2ad139f78a52edd85b1cc4e32f2e962d0/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py#L235 + - ex. - `is_recording()` optimization on non-sampled spans - - ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py#L133 + - ex. - Appropriate error handling - - ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py#L146 - + - ex. ## Expectations from contributors OpenTelemetry is an open source community, and as such, greatly encourages contributions from anyone interested in the project. With that being said, there is a certain level of expectation from contributors even after a pull request is merged, specifically pertaining to instrumentations. The OpenTelemetry Python community expects contributors to maintain a level of support and interest in the instrumentations they contribute. This is to ensure that the instrumentation does not become stale and still functions the way the original contributor intended. Some instrumentations also pertain to libraries that the current members of the community are not so familiar with, so it is necessary to rely on the expertise of the original contributing parties. - diff --git a/README.md b/README.md index 0a3d37ab3f..133acf81f6 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,20 @@ --- -## OpenTelemetry Python Contrib +# OpenTelemetry Python Contrib The Python auto-instrumentation libraries for [OpenTelemetry](https://opentelemetry.io/) (per [OTEP 0001](https://github.com/open-telemetry/oteps/blob/main/text/0001-telemetry-without-manual-instrumentation.md)) -### Installation +## Index + +* [Installation](#installation) +* [Releasing](#releasing) + * [Releasing a package as `1.0` stable](#releasing-a-package-as-10-stable) +* [Contributing](#contributing) +* [Running Tests Locally](#running-tests-locally) +* [Thanks to all the people who already contributed](#thanks-to-all-the-people-who-already-contributed) + +## Installation This repository includes installable packages for each instrumented library. Libraries that produce telemetry data should only depend on `opentelemetry-api`, and defer the choice of the SDK to the application developer. Applications may @@ -79,6 +88,7 @@ To resolve this, members of the community are encouraged to commit to becoming a ### Releasing a package as `1.0` stable To release a package as `1.0` stable, the package: + - SHOULD have a CODEOWNER. To become one, submit an issue and explain why you meet the responsibilities found in [CODEOWNERS](.github/CODEOWNERS). - MUST have unit tests that cover all supported versions of the instrumented library. - e.g. Instrumentation packages might use different techniques to instrument different major versions of python packages @@ -86,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). @@ -98,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).* @@ -119,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).* @@ -131,9 +151,8 @@ Emeritus Maintainers: 4. Make sure you have `tox` installed. `pip install tox`. 5. Run tests for a package. (e.g. `tox -e test-instrumentation-flask`.) -### Thanks to all the people who already contributed! +### Thanks to all the people who already contributed - diff --git a/RELEASING.md b/RELEASING.md index 1547cec224..256674d1b8 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -77,15 +77,17 @@ * If for some reason the action failed, see [Publish failed](#publish-failed) below * Move stable tag * Run the following (TODO automate): + ```bash git tag -d stable git tag stable git push --delete origin tagname git push origin stable ``` + * This will ensure the docs are pointing at the stable release. * To validate this worked, ensure the stable build has run successfully: - https://readthedocs.org/projects/opentelemetry-python/builds/. + . If the build has not run automatically, it can be manually trigger via the readthedocs interface. ## Troubleshooting @@ -98,4 +100,4 @@ If for some reason the action failed, do it manually: - Build distributions with `./scripts/build.sh` - Delete distributions we don't want to push (e.g. `testutil`) - Push to PyPI as `twine upload --skip-existing --verbose dist/*` -- Double check PyPI! \ No newline at end of file +- Double check PyPI! 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/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 3cde0bd1ac..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 @@ -1,11 +1,11 @@ #!/bin/bash +set -e PROM_VERSION=v2.39.0 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/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/instrumentation/README.md b/instrumentation/README.md index 0cce7e5de7..284037d707 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 | experimental +| [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 | experimental \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/README.rst b/instrumentation/opentelemetry-instrumentation-aio-pika/README.rst index aa0f1a3f5c..bb5e46cf2f 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/README.rst +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/README.rst @@ -18,6 +18,6 @@ Installation References ---------- -* `OpenTelemetry Aio-pika instrumentation `_ +* `OpenTelemetry Aio-pika instrumentation `_ * `OpenTelemetry Project `_ * `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aio-pika/pyproject.toml index f328eab452..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", ] @@ -33,12 +33,6 @@ dependencies = [ instruments = [ "aio_pika >= 7.2.0, < 10.0.0", ] -test = [ - "opentelemetry-instrumentation-aio-pika[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "pytest", - "wrapt >= 1.0.0, < 2.0.0", -] [project.entry-points.opentelemetry_instrumentor] aio-pika = "opentelemetry.instrumentation.aio_pika:AioPikaInstrumentor" 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-0.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-0.txt new file mode 100644 index 0000000000..c8ffea4e89 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-0.txt @@ -0,0 +1,23 @@ +aio-pika==7.2.0 +aiormq==6.2.3 +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.1.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-aio-pika/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt new file mode 100644 index 0000000000..1e2ea5a1e5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt @@ -0,0 +1,23 @@ +aio-pika==8.3.0 +aiormq==6.6.4 +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.2.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.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-aio-pika/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt new file mode 100644 index 0000000000..3250c93947 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt @@ -0,0 +1,23 @@ +aio-pika==9.4.0 +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-aio-pika/tests/test_publish_decorator.py b/instrumentation/opentelemetry-instrumentation-aio-pika/tests/test_publish_decorator.py index 41cd11d5a6..90a029531d 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/tests/test_publish_decorator.py +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/tests/test_publish_decorator.py @@ -75,9 +75,7 @@ def _test_publish(self, exchange_type: Type[Exchange]): with mock.patch.object( PublishDecorator, "_get_publish_span" ) as mock_get_publish_span: - with mock.patch.object( - Exchange, "publish", return_value=asyncio.sleep(0) - ) as mock_publish: + with mock.patch.object(Exchange, "publish") as mock_publish: decorated_publish = PublishDecorator( self.tracer, exchange ).decorate(mock_publish) @@ -101,9 +99,7 @@ def _test_publish_works_with_not_recording_span(self, exchange_type): mocked_not_recording_span = MagicMock() mocked_not_recording_span.is_recording.return_value = False mock_get_publish_span.return_value = mocked_not_recording_span - with mock.patch.object( - Exchange, "publish", return_value=asyncio.sleep(0) - ) as mock_publish: + with mock.patch.object(Exchange, "publish") as mock_publish: with mock.patch( "opentelemetry.instrumentation.aio_pika.publish_decorator.propagate.inject" ) as mock_inject: @@ -158,9 +154,7 @@ def _test_publish(self, exchange_type: Type[Exchange]): with mock.patch.object( PublishDecorator, "_get_publish_span" ) as mock_get_publish_span: - with mock.patch.object( - Exchange, "publish", return_value=asyncio.sleep(0) - ) as mock_publish: + with mock.patch.object(Exchange, "publish") as mock_publish: decorated_publish = PublishDecorator( self.tracer, exchange ).decorate(mock_publish) @@ -184,9 +178,7 @@ def _test_publish_works_with_not_recording_span(self, exchange_type): mocked_not_recording_span = MagicMock() mocked_not_recording_span.is_recording.return_value = False mock_get_publish_span.return_value = mocked_not_recording_span - with mock.patch.object( - Exchange, "publish", return_value=asyncio.sleep(0) - ) as mock_publish: + with mock.patch.object(Exchange, "publish") as mock_publish: with mock.patch( "opentelemetry.instrumentation.aio_pika.publish_decorator.propagate.inject" ) as mock_inject: diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-client/pyproject.toml index 9aac42647a..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", ] @@ -35,10 +35,6 @@ dependencies = [ instruments = [ "aiohttp ~= 3.0", ] -test = [ - "opentelemetry-instrumentation-aiohttp-client[instruments]", - "http-server-mock" -] [project.entry-points.opentelemetry_instrumentor] aiohttp-client = "opentelemetry.instrumentation.aiohttp_client:AioHttpClientInstrumentor" 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-client/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt new file mode 100644 index 0000000000..b8ccfd2a50 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt @@ -0,0 +1,37 @@ +aiohttp==3.9.3 +aiosignal==1.3.1 +asgiref==3.7.2 +async-timeout==4.0.3 +attrs==23.2.0 +blinker==1.7.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +click==8.1.7 +Deprecated==1.2.14 +Flask==3.0.2 +frozenlist==1.4.1 +http_server_mock==1.7 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +multidict==6.0.5 +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 +Werkzeug==3.0.1 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-aiohttp-client diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 566f9dbb35..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", ] @@ -35,11 +35,6 @@ dependencies = [ instruments = [ "aiohttp ~= 3.0", ] -test = [ - "opentelemetry-instrumentation-aiohttp-server[instruments]", - "pytest-asyncio", - "pytest-aiohttp", -] [project.entry-points.opentelemetry_instrumentor] aiohttp-server = "opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 914f005b2a..c1ab960818 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -207,7 +207,7 @@ async def middleware(request, handler): duration_histogram = meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) active_requests_counter = meter.create_up_down_counter( 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-aiohttp-server/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt new file mode 100644 index 0000000000..9f6d7accce --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt @@ -0,0 +1,27 @@ +aiohttp==3.9.3 +aiosignal==1.3.1 +asgiref==3.7.2 +async-timeout==4.0.3 +attrs==23.2.0 +Deprecated==1.2.14 +frozenlist==1.4.1 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +multidict==6.0.5 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-aiohttp==1.0.5 +pytest-asyncio==0.23.5 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-aiohttp-server diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiopg/pyproject.toml index ebb88ee0ba..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", ] @@ -34,11 +34,6 @@ dependencies = [ instruments = [ "aiopg >= 0.13.0, < 2.0.0", ] -test = [ - "opentelemetry-instrumentation-aiopg[instruments]", - "opentelemetry-semantic-conventions == 0.45b0.dev", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] aiopg = "opentelemetry.instrumentation.aiopg:AiopgInstrumentor" 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-aiopg/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt new file mode 100644 index 0000000000..2b03677f42 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt @@ -0,0 +1,22 @@ +aiopg==1.4.0 +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 +install==1.3.5 +packaging==23.2 +pluggy==1.4.0 +psycopg2-binary==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-aiopg diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py b/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py index c6d00a51fe..fb76bd0f38 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py @@ -76,7 +76,7 @@ def test_instrumentor_connect(self): cnx = async_call(aiopg.connect(database="test")) cursor = async_call(cnx.cursor()) query = "SELECT * FROM test" - cursor.execute(query) + async_call(cursor.execute(query)) spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) @@ -127,7 +127,7 @@ def test_instrumentor_create_pool(self): cnx = async_call(pool.acquire()) cursor = async_call(cnx.cursor()) query = "SELECT * FROM test" - cursor.execute(query) + async_call(cursor.execute(query)) spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) diff --git a/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml index d642a07e48..a4072bac7d 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asgi/pyproject.toml @@ -26,19 +26,15 @@ 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] instruments = [ "asgiref ~= 3.0", ] -test = [ - "opentelemetry-instrumentation-asgi[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-asgi" 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 dba7414cb1..8e4d699cbb 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -195,7 +195,7 @@ def client_response_hook(span: Span, message: dict): import urllib from functools import wraps from timeit import default_timer -from typing import Any, Awaitable, Callable, Tuple, cast +from typing import Any, Awaitable, Callable, Tuple from asgiref.compatibility import guarantee_single_callable @@ -347,11 +347,17 @@ def collect_custom_headers_attributes( - 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: dict[str, str] = { - _key.decode("utf8"): _value.decode("utf8") - for (_key, _value) in scope_or_response_message.get("headers") - or cast("list[tuple[bytes, bytes]]", []) - } + headers: dict[str, str] = {} + raw_headers = scope_or_response_message.get("headers") + if raw_headers: + for _key, _value in raw_headers: + key = _key.decode().lower() + value = _value.decode() + if key in headers: + headers[key] += f",{value}" + else: + headers[key] = value + return sanitize.sanitize_header_values( headers, header_regexes, @@ -492,7 +498,7 @@ def __init__( self.duration_histogram = self.meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) self.server_response_size_histogram = self.meter.create_histogram( name=MetricInstruments.HTTP_SERVER_RESPONSE_SIZE, @@ -666,7 +672,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 @@ -697,7 +705,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/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt new file mode 100644 index 0000000000..f3ee9764cf --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asgi/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 util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-asgi diff --git a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py index c50839f72f..7a9c91a3e7 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py @@ -40,6 +40,24 @@ async def http_app_with_custom_headers(scope, receive, send): await send({"type": "http.response.body", "body": b"*"}) +async def http_app_with_repeat_headers(scope, receive, send): + message = await receive() + assert scope["type"] == "http" + if message.get("type") == "http.request": + await send( + { + "type": "http.response.start", + "status": 200, + "headers": [ + (b"Content-Type", b"text/plain"), + (b"custom-test-header-1", b"test-header-value-1"), + (b"custom-test-header-1", b"test-header-value-2"), + ], + } + ) + await send({"type": "http.response.body", "body": b"*"}) + + async def websocket_app_with_custom_headers(scope, receive, send): assert scope["type"] == "websocket" while True: @@ -121,6 +139,25 @@ def test_http_custom_request_headers_in_span_attributes(self): if span.kind == SpanKind.SERVER: self.assertSpanHasAttributes(span, expected) + def test_http_repeat_request_headers_in_span_attributes(self): + self.scope["headers"].extend( + [ + (b"custom-test-header-1", b"test-header-value-1"), + (b"custom-test-header-1", b"test-header-value-2"), + ] + ) + self.seed_app(self.app) + self.send_default_request() + self.get_all_output() + span_list = self.exporter.get_finished_spans() + expected = { + "http.request.header.custom_test_header_1": ( + "test-header-value-1,test-header-value-2", + ), + } + span = next(span for span in span_list if span.kind == SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + def test_http_custom_request_headers_not_in_span_attributes(self): self.scope["headers"].extend( [ @@ -176,6 +213,24 @@ def test_http_custom_response_headers_in_span_attributes(self): if span.kind == SpanKind.SERVER: self.assertSpanHasAttributes(span, expected) + def test_http_repeat_response_headers_in_span_attributes(self): + self.app = otel_asgi.OpenTelemetryMiddleware( + http_app_with_repeat_headers, + tracer_provider=self.tracer_provider, + **self.constructor_params, + ) + self.seed_app(self.app) + self.send_default_request() + self.get_all_output() + span_list = self.exporter.get_finished_spans() + expected = { + "http.response.header.custom_test_header_1": ( + "test-header-value-1,test-header-value-2", + ), + } + span = next(span for span in span_list if span.kind == SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + def test_http_custom_response_headers_not_in_span_attributes(self): self.app = otel_asgi.OpenTelemetryMiddleware( http_app_with_custom_headers, 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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 358fbefeb4..540da184be 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -25,20 +25,14 @@ 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", ] [project.optional-dependencies] instruments = [] -test = [ - "opentelemetry-instrumentation-asyncio[instruments]", - "pytest", - "wrapt >= 1.0.0, < 2.0.0", - "pytest-asyncio", -] [project.entry-points.opentelemetry_instrumentor] asyncio = "opentelemetry.instrumentation.asyncio:AsyncioInstrumentor" 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-asyncio/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt new file mode 100644 index 0000000000..14f724888b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/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-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-asyncio 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/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/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..8f29a0ec38 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,20 +340,30 @@ 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 try: result = call_wrapped(*args, **kwargs) 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..51ebb67ebc 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 @@ -54,7 +54,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 +145,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 + ], }, ) 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/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/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-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/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/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/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/__init__.py b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py index 94cac68b70..10ccca1270 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/__init__.py @@ -113,10 +113,8 @@ def keys(self, carrier): class CeleryInstrumentor(BaseInstrumentor): - def __init__(self): - super().__init__() - self.metrics = None - self.task_id_to_start_time = {} + metrics = None + task_id_to_start_time = {} def instrumentation_dependencies(self) -> Collection[str]: return _instruments 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_duplicate.py b/instrumentation/opentelemetry-instrumentation-celery/tests/test_duplicate.py new file mode 100644 index 0000000000..ab1f7804cf --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-celery/tests/test_duplicate.py @@ -0,0 +1,30 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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.instrumentation.celery import CeleryInstrumentor + + +class TestUtils(unittest.TestCase): + def test_duplicate_instrumentaion(self): + first = CeleryInstrumentor() + first.instrument() + second = CeleryInstrumentor() + second.instrument() + CeleryInstrumentor().uninstrument() + self.assertIsNotNone(first.metrics) + self.assertIsNotNone(second.metrics) + self.assertEqual(first.task_id_to_start_time, {}) + self.assertEqual(second.task_id_to_start_time, {}) 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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml index 3032c12da6..e726768535 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-dbapi/pyproject.toml @@ -25,16 +25,13 @@ 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 = [] -test = [ - "opentelemetry-test-utils == 0.45b0.dev", -] [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-dbapi" 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-dbapi/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt new file mode 100644 index 0000000000..46c02707c1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-dbapi/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-dbapi diff --git a/instrumentation/opentelemetry-instrumentation-django/pyproject.toml b/instrumentation/opentelemetry-instrumentation-django/pyproject.toml index 50cc227e44..c8869d7b29 100644 --- a/instrumentation/opentelemetry-instrumentation-django/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-django/pyproject.toml @@ -25,23 +25,19 @@ 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", ] -test = [ - "opentelemetry-instrumentation-django[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] django = "opentelemetry.instrumentation.django:DjangoInstrumentor" diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py index 583f1adeb6..37ac760283 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py @@ -322,7 +322,7 @@ def _instrument(self, **kwargs): _DjangoMiddleware._duration_histogram = meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound http request", + description="Duration of HTTP client requests.", ) _DjangoMiddleware._active_request_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, 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-0.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt new file mode 100644 index 0000000000..6dce957000 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +Django==2.2.28 +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 +pytz==2024.1 +sqlparse==0.4.4 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-django diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt new file mode 100644 index 0000000000..548db1b8e3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt @@ -0,0 +1,23 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +Django==3.2.25 +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 +pytz==2024.1 +sqlparse==0.4.4 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e instrumentation/opentelemetry-instrumentation-asgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-django diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt new file mode 100644 index 0000000000..0970d2f253 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt @@ -0,0 +1,23 @@ +asgiref==3.7.2 +attrs==23.2.0 +backports.zoneinfo==0.2.1 +Deprecated==1.2.14 +Django==4.2.11 +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 +sqlparse==0.4.4 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e instrumentation/opentelemetry-instrumentation-asgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-django diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt new file mode 100644 index 0000000000..d853c05877 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +Django==4.2.11 +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 +sqlparse==0.4.4 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e instrumentation/opentelemetry-instrumentation-asgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-django diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index d7bb1e544f..4d221fae62 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -390,7 +390,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 +398,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-elasticsearch/pyproject.toml b/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml index c716769f5c..f5ba221b7f 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/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", "wrapt >= 1.0.0, < 2.0.0", ] [project.optional-dependencies] instruments = [ - "elasticsearch >= 2.0", -] -test = [ - "opentelemetry-instrumentation-elasticsearch[instruments]", - "elasticsearch-dsl >= 2.0", - "opentelemetry-test-utils == 0.45b0.dev", + "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..0f5056de83 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-6.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt new file mode 100644 index 0000000000..4bd1d0d318 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt @@ -0,0 +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 +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.10.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-elasticsearch 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/test_elasticsearch.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py index 0c84cf5cd6..5d1c85f77d 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py @@ -44,13 +44,11 @@ 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 + @mock.patch( "elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request" @@ -486,3 +484,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 = Elasticsearch() + es.bulk( + [ + { + "_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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-falcon/pyproject.toml index 1e4b5e5254..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", ] @@ -36,10 +36,6 @@ dependencies = [ instruments = [ "falcon >= 1.4.1, < 3.1.2", ] -test = [ - "opentelemetry-instrumentation-falcon[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] falcon = "opentelemetry.instrumentation.falcon:FalconInstrumentor" 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 d6cf8249a4..06a550cf3f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -268,7 +268,7 @@ def __init__(self, *args, **kwargs): self.duration_histogram = self._otel_meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) self.active_requests_counter = self._otel_meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, 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/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-0.txt new file mode 100644 index 0000000000..31c7f1d7c8 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-0.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +falcon==1.4.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 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-mimeparse==1.6.0 +six==1.16.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-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-falcon diff --git a/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt new file mode 100644 index 0000000000..ad476d7c22 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +falcon==2.0.0 +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 instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-falcon diff --git a/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt new file mode 100644 index 0000000000..6c5c3e8ac9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +falcon==3.1.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 +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-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-falcon 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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml index 4df6d3760c..0e11179de2 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-fastapi/pyproject.toml @@ -25,22 +25,16 @@ 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] instruments = [ "fastapi ~= 0.58", ] -test = [ - "opentelemetry-instrumentation-fastapi[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "requests ~= 2.23", # needed for testclient - "httpx ~= 0.22", # needed for testclient -] [project.entry-points.opentelemetry_instrumentor] fastapi = "opentelemetry.instrumentation.fastapi:FastAPIInstrumentor" 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-fastapi/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt new file mode 100644 index 0000000000..8d7bf3ad78 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt @@ -0,0 +1,35 @@ +annotated-types==0.6.0 +anyio==4.3.0 +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +Deprecated==1.2.14 +exceptiongroup==1.2.0 +fastapi==0.109.2 +h11==0.14.0 +httpcore==1.0.4 +httpx==0.27.0 +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 +pydantic==2.6.2 +pydantic_core==2.16.3 +pytest==7.1.3 +pytest-benchmark==4.0.0 +requests==2.31.0 +sniffio==1.3.0 +starlette==0.36.3 +tomli==2.0.1 +typing_extensions==4.9.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-asgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-fastapi diff --git a/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml b/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml index ca26f4c860..2bc1335a51 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-flask/pyproject.toml @@ -25,22 +25,18 @@ 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", ] [project.optional-dependencies] instruments = [ "flask >= 1.0", ] -test = [ - "opentelemetry-instrumentation-flask[instruments]", - "markupsafe==2.1.2", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] flask = "opentelemetry.instrumentation.flask:FlaskInstrumentor" 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 5e81cc5abe..ba1031655e 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -245,22 +245,13 @@ def response_hook(span: Span, status: str, response_headers: List): from typing import Collection import flask +import importlib_metadata as metadata from packaging import version as package_version import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import context, trace from opentelemetry.instrumentation.flask.package import _instruments from opentelemetry.instrumentation.flask.version import __version__ - -try: - flask_version = flask.__version__ -except AttributeError: - try: - from importlib import metadata - except ImportError: - import importlib_metadata as metadata - flask_version = metadata.version("flask") - from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.propagators import ( get_global_response_propagator, @@ -281,6 +272,8 @@ def response_hook(span: Span, status: str, response_headers: List): _excluded_urls_from_env = get_excluded_urls("FLASK") +flask_version = metadata.version("flask") + if package_version.parse(flask_version) >= package_version.parse("2.2.0"): def _request_ctx_ref() -> weakref.ReferenceType: @@ -513,7 +506,7 @@ def __init__(self, *args, **kwargs): duration_histogram = meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, @@ -619,7 +612,7 @@ def instrument_app( duration_histogram = meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, 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/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-0.txt new file mode 100644 index 0000000000..fbefeebdb4 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-0.txt @@ -0,0 +1,25 @@ +asgiref==3.7.2 +attrs==23.2.0 +click==8.1.7 +Deprecated==1.2.14 +Flask==2.1.3 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.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 +Werkzeug==2.3.8 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-flask diff --git a/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt new file mode 100644 index 0000000000..41583ad7f9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt @@ -0,0 +1,25 @@ +asgiref==3.7.2 +attrs==23.2.0 +click==8.1.7 +Deprecated==1.2.14 +Flask==2.2.0 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.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 +Werkzeug==2.3.8 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-flask diff --git a/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt new file mode 100644 index 0000000000..3a89328861 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt @@ -0,0 +1,26 @@ +asgiref==3.7.2 +attrs==23.2.0 +blinker==1.7.0 +click==8.1.7 +Deprecated==1.2.14 +Flask==3.0.2 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.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 +Werkzeug==3.0.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-flask diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py index 6117521bb9..3c8073f261 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py @@ -88,6 +88,14 @@ def _custom_response_headers(): resp.headers["my-secret-header"] = "my-secret-value" return resp + @staticmethod + def _repeat_custom_response_headers(): + headers = { + "content-type": "text/plain; charset=utf-8", + "my-custom-header": ["my-custom-value-1", "my-custom-header-2"], + } + return flask.Response("test response", headers=headers) + def _common_initialization(self): def excluded_endpoint(): return "excluded" @@ -106,6 +114,9 @@ def excluded2_endpoint(): self.app.route("/test_custom_response_headers")( self._custom_response_headers ) + self.app.route("/test_repeat_custom_response_headers")( + self._repeat_custom_response_headers + ) # pylint: disable=attribute-defined-outside-init self.client = Client(self.app, Response) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index 3bd2f74ba8..82ca88460c 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -18,17 +18,17 @@ from flask import Flask, request from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _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 +54,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", @@ -69,8 +70,8 @@ def expected_attributes(override_attributes): "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, } @@ -358,6 +359,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 +367,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, } self._assert_basic_metric( expected_duration_attributes, @@ -374,20 +378,23 @@ 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, @@ -410,6 +417,7 @@ def test_basic_metric_nonstandard_http_method_allowed_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 405, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "NONSTANDARD", @@ -417,6 +425,8 @@ def test_basic_metric_nonstandard_http_method_allowed_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, @@ -671,6 +681,22 @@ def test_custom_request_header_added_in_server_span(self): self.assertEqual(span.kind, trace.SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) + def test_repeat_custom_request_header_added_in_server_span(self): + headers = [ + ("Custom-Test-Header-1", "Test Value 1"), + ("Custom-Test-Header-1", "Test Value 2"), + ] + resp = self.client.get("/hello/123", headers=headers) + self.assertEqual(200, resp.status_code) + span = self.memory_exporter.get_finished_spans()[0] + expected = { + "http.request.header.custom_test_header_1": ( + "Test Value 1, Test Value 2", + ), + } + self.assertEqual(span.kind, trace.SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + def test_custom_request_header_not_added_in_internal_span(self): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("test", kind=trace.SpanKind.SERVER): @@ -724,6 +750,21 @@ def test_custom_response_header_added_in_server_span(self): self.assertEqual(span.kind, trace.SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) + def test_repeat_custom_response_header_added_in_server_span(self): + resp = self.client.get("/test_repeat_custom_response_headers") + self.assertEqual(resp.status_code, 200) + span = self.memory_exporter.get_finished_spans()[0] + expected = { + "http.response.header.content_type": ( + "text/plain; charset=utf-8", + ), + "http.response.header.my_custom_header": ( + "my-custom-value-1,my-custom-header-2", + ), + } + self.assertEqual(span.kind, trace.SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + def test_custom_response_header_not_added_in_internal_span(self): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("test", kind=trace.SpanKind.SERVER): 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/_aio_server.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_server.py index 0db4c36edf..ba255ef3bf 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_server.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_server.py @@ -17,9 +17,9 @@ import wrapt from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace.status import Status, StatusCode from ._server import OpenTelemetryServerInterceptor, _wrap_rpc_behavior +from ._utilities import _server_status # pylint:disable=abstract-method @@ -36,12 +36,8 @@ async def abort(self, code, details="", trailing_metadata=tuple()): self._self_active_span.set_attribute( SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0] ) - self._self_active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{code}:{details}", - ) - ) + status = _server_status(code, details) + self._self_active_span.set_status(status) return await self.__wrapped__.abort(code, details, trailing_metadata) def set_code(self, code): @@ -51,23 +47,15 @@ def set_code(self, code): SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0] ) if code != grpc.StatusCode.OK: - self._self_active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{code}:{details}", - ) - ) + status = _server_status(code, details) + self._self_active_span.set_status(status) return self.__wrapped__.set_code(code) def set_details(self, details): self._self_details = details if self._self_code != grpc.StatusCode.OK: - self._self_active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{self._self_code}:{details}", - ) - ) + status = _server_status(self._self_code, details) + self._self_active_span.set_status(status) return self.__wrapped__.set_details(details) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py index 9b66110574..71697ef8bc 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_server.py @@ -31,7 +31,8 @@ from opentelemetry.context import attach, detach from opentelemetry.propagate import extract from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace.status import Status, StatusCode + +from ._utilities import _server_status logger = logging.getLogger(__name__) @@ -124,12 +125,8 @@ def abort(self, code, details): self._active_span.set_attribute( SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0] ) - self._active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{code}:{details}", - ) - ) + status = _server_status(code, details) + self._active_span.set_status(status) return self._servicer_context.abort(code, details) def abort_with_status(self, status): @@ -158,23 +155,15 @@ def set_code(self, code): SpanAttributes.RPC_GRPC_STATUS_CODE, code.value[0] ) if code != grpc.StatusCode.OK: - self._active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{code}:{details}", - ) - ) + status = _server_status(code, details) + self._active_span.set_status(status) return self._servicer_context.set_code(code) def set_details(self, details): self._details = details if self._code != grpc.StatusCode.OK: - self._active_span.set_status( - Status( - status_code=StatusCode.ERROR, - description=f"{self._code}:{details}", - ) - ) + status = _server_status(self._code, details) + self._active_span.set_status(status) return self._servicer_context.set_details(details) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_utilities.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_utilities.py index b6ff7d311a..8a6365b742 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_utilities.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_utilities.py @@ -14,6 +14,10 @@ """Internal utilities.""" +import grpc + +from opentelemetry.trace.status import Status, StatusCode + class RpcInfo: def __init__( @@ -31,3 +35,21 @@ def __init__( self.request = request self.response = response self.error = error + + +def _server_status(code, details): + error_status = Status( + status_code=StatusCode.ERROR, description=f"{code}:{details}" + ) + status_codes = { + grpc.StatusCode.UNKNOWN: error_status, + grpc.StatusCode.DEADLINE_EXCEEDED: error_status, + grpc.StatusCode.UNIMPLEMENTED: error_status, + grpc.StatusCode.INTERNAL: error_status, + grpc.StatusCode.UNAVAILABLE: error_status, + grpc.StatusCode.DATA_LOSS: error_status, + } + + return status_codes.get( + code, Status(status_code=StatusCode.UNSET, description="") + ) 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/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_aio_server_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_server_interceptor.py index 242295c08c..7b31b085de 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_server_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_server_interceptor.py @@ -507,9 +507,7 @@ async def test_abort(self): class AbortServicer(GRPCTestServerServicer): # pylint:disable=C0103 async def SimpleMethod(self, request, context): - await context.abort( - grpc.StatusCode.FAILED_PRECONDITION, failure_message - ) + await context.abort(grpc.StatusCode.INTERNAL, failure_message) testcase = self @@ -520,9 +518,7 @@ async def request(channel): with testcase.assertRaises(grpc.RpcError) as cm: await channel.unary_unary(rpc_call)(msg) - self.assertEqual( - cm.exception.code(), grpc.StatusCode.FAILED_PRECONDITION - ) + self.assertEqual(cm.exception.code(), grpc.StatusCode.INTERNAL) self.assertEqual(cm.exception.details(), failure_message) await run_with_test_server(request, servicer=AbortServicer()) @@ -543,7 +539,7 @@ async def request(channel): self.assertEqual(span.status.status_code, StatusCode.ERROR) self.assertEqual( span.status.description, - f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}", + f"{grpc.StatusCode.INTERNAL}:{failure_message}", ) # Check attributes @@ -555,7 +551,7 @@ async def request(channel): SpanAttributes.RPC_METHOD: "SimpleMethod", SpanAttributes.RPC_SERVICE: "GRPCTestServer", SpanAttributes.RPC_SYSTEM: "grpc", - SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.FAILED_PRECONDITION.value[ + SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.INTERNAL.value[ 0 ], }, @@ -605,11 +601,8 @@ async def request(channel): ) # make sure this span errored, with the right status and detail - self.assertEqual(span.status.status_code, StatusCode.ERROR) - self.assertEqual( - span.status.description, - f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}", - ) + self.assertEqual(span.status.status_code, StatusCode.UNSET) + self.assertEqual(span.status.description, None) # Check attributes self.assertSpanHasAttributes( diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_server_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_server_interceptor.py index 57f27c89d6..de79269894 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_server_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_server_interceptor.py @@ -552,28 +552,45 @@ def test_abort(self): # our detailed failure message failure_message = "This is a test failure" - # aborting RPC handler - def handler(request, context): + # aborting RPC handlers + def error_status_handler(request, context): + context.abort(grpc.StatusCode.INTERNAL, failure_message) + + def unset_status_handler(request, context): context.abort(grpc.StatusCode.FAILED_PRECONDITION, failure_message) - with self.server( - max_workers=1, - interceptors=[interceptor], - ) as (server, channel): - server.add_generic_rpc_handlers((UnaryUnaryRpcHandler(handler),)) - rpc_call = "TestServicer/handler" + rpc_call_error = "TestServicer/error_status_handler" + rpc_call_unset = "TestServicer/unset_status_handler" + + rpc_calls = { + rpc_call_error: error_status_handler, + rpc_call_unset: unset_status_handler, + } + + for rpc_call, handler in rpc_calls.items(): + with self.server( + max_workers=1, + interceptors=[interceptor], + ) as (server, channel): + server.add_generic_rpc_handlers( + (UnaryUnaryRpcHandler(handler),) + ) - server.start() - # unfortunately, these are just bare exceptions in grpc... - with self.assertRaises(Exception): - channel.unary_unary(rpc_call)(b"") - server.stop(None) + server.start() + + with self.assertRaises(Exception): + channel.unary_unary(rpc_call)(b"") + + # unfortunately, these are just bare exceptions in grpc... + server.stop(None) spans_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans_list), 1) + self.assertEqual(len(spans_list), 2) + + # check error span span = spans_list[0] - self.assertEqual(span.name, rpc_call) + self.assertEqual(span.name, rpc_call_error) self.assertIs(span.kind, trace.SpanKind.SERVER) # Check version and name in span's instrumentation info @@ -585,15 +602,43 @@ def handler(request, context): self.assertEqual(span.status.status_code, StatusCode.ERROR) self.assertEqual( span.status.description, - f"{grpc.StatusCode.FAILED_PRECONDITION}:{failure_message}", + f"{grpc.StatusCode.INTERNAL}:{failure_message}", + ) + + # Check attributes + self.assertSpanHasAttributes( + span, + { + **self.net_peer_span_attributes, + SpanAttributes.RPC_METHOD: "error_status_handler", + SpanAttributes.RPC_SERVICE: "TestServicer", + SpanAttributes.RPC_SYSTEM: "grpc", + SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.INTERNAL.value[ + 0 + ], + }, ) + # check unset status span + span = spans_list[1] + + self.assertEqual(span.name, rpc_call_unset) + self.assertIs(span.kind, trace.SpanKind.SERVER) + + # Check version and name in span's instrumentation info + self.assertEqualSpanInstrumentationInfo( + span, opentelemetry.instrumentation.grpc + ) + + self.assertEqual(span.status.description, None) + self.assertEqual(span.status.status_code, StatusCode.UNSET) + # Check attributes self.assertSpanHasAttributes( span, { **self.net_peer_span_attributes, - SpanAttributes.RPC_METHOD: "handler", + SpanAttributes.RPC_METHOD: "unset_status_handler", SpanAttributes.RPC_SERVICE: "TestServicer", SpanAttributes.RPC_SYSTEM: "grpc", SpanAttributes.RPC_GRPC_STATUS_CODE: grpc.StatusCode.FAILED_PRECONDITION.value[ diff --git a/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml b/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml index f13fa816bc..e4e5575d96 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-httpx/pyproject.toml @@ -25,20 +25,15 @@ 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] instruments = [ "httpx >= 0.18.0", ] -test = [ - "opentelemetry-instrumentation-httpx[instruments]", - "opentelemetry-sdk ~= 1.12", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] httpx = "opentelemetry.instrumentation.httpx:HTTPXClientInstrumentor" 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..e6609157c4 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 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/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-0.txt new file mode 100644 index 0000000000..2d3a8399d8 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-0.txt @@ -0,0 +1,28 @@ +anyio==3.7.1 +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +Deprecated==1.2.14 +exceptiongroup==1.2.0 +h11==0.12.0 +httpcore==0.13.7 +httpx==0.18.2 +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 +respx==0.17.1 +rfc3986==1.5.0 +sniffio==1.3.1 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-httpx diff --git a/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt new file mode 100644 index 0000000000..4a36398fc1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt @@ -0,0 +1,27 @@ +anyio==4.3.0 +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +Deprecated==1.2.14 +exceptiongroup==1.2.0 +h11==0.14.0 +httpcore==1.0.4 +httpx==0.27.0 +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 +respx==0.20.2 +sniffio==1.3.1 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-httpx 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/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/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/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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml index de8c31a1f3..c9db02e22f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/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 = [ "mysqlclient < 3", ] -test = [ - "opentelemetry-instrumentation-mysqlclient[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] mysqlclient = "opentelemetry.instrumentation.mysqlclient:MySQLClientInstrumentor" 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-mysqlclient/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt new file mode 100644 index 0000000000..afa2ccae6c --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/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 +mysqlclient==2.2.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 +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-mysqlclient 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..76261c89ce 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 @@ -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..5afa5d9ee6 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 @@ -128,7 +133,7 @@ def decorated_function( def _get_span( tracer: Tracer, - channel: Channel, + channel: Optional[Channel], properties: BasicProperties, task_name: str, destination: str, @@ -157,7 +162,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 +181,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 +197,75 @@ 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/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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pymemcache/pyproject.toml index e7a642b0aa..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", ] @@ -34,10 +34,6 @@ dependencies = [ instruments = [ "pymemcache >= 1.3.5, < 5", ] -test = [ - "opentelemetry-instrumentation-pymemcache[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] pymemcache = "opentelemetry.instrumentation.pymemcache:PymemcacheInstrumentor" 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/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-0.txt new file mode 100644 index 0000000000..2e7313ab6e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-0.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 +pymemcache==1.3.5 +pytest==7.1.3 +pytest-benchmark==4.0.0 +six==1.16.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-pymemcache diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-1.txt new file mode 100644 index 0000000000..a1a3cc4fb1 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/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 +py==1.11.0 +py-cpuinfo==9.0.0 +pymemcache==2.2.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +six==1.16.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-pymemcache diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.txt new file mode 100644 index 0000000000..cb28ea22d7 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.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 +pymemcache==3.4.1 +pytest==7.1.3 +pytest-benchmark==4.0.0 +six==1.16.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-pymemcache diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.txt new file mode 100644 index 0000000000..40152664ac --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.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 +pymemcache==3.4.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +six==1.16.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-pymemcache diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt new file mode 100644 index 0000000000..9031276ce4 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.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 +pymemcache==4.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-pymemcache 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/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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-pyramid/pyproject.toml index 1face37ccc..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", ] @@ -36,11 +36,6 @@ dependencies = [ instruments = [ "pyramid >= 1.7", ] -test = [ - "opentelemetry-instrumentation-pyramid[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "werkzeug == 0.16.1", -] [project.entry-points.opentelemetry_instrumentor] pyramid = "opentelemetry.instrumentation.pyramid:PyramidInstrumentor" 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 e3675fcfab..4f17da3da5 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -140,7 +140,7 @@ def trace_tween_factory(handler, registry): duration_histogram = meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration of the inbound HTTP request", + description="Duration of HTTP client requests.", ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, 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/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt new file mode 100644 index 0000000000..1362e7166e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt @@ -0,0 +1,30 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +hupper==1.12.1 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +PasteDeploy==3.1.0 +plaster==1.1.2 +plaster-pastedeploy==1.0.1 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pyramid==2.0.2 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +translationstring==1.4 +typing_extensions==4.9.0 +venusian==3.1.0 +WebOb==1.8.7 +Werkzeug==0.16.1 +wrapt==1.16.0 +zipp==3.17.0 +zope.deprecation==5.0 +zope.interface==6.2 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-wsgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-pyramid 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/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/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/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-remoulade/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt new file mode 100644 index 0000000000..c50dfde9b5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/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 +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.9.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-remoulade diff --git a/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml b/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml index a4f8255e00..6252ab3de9 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml @@ -25,20 +25,15 @@ 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] instruments = [ "requests ~= 2.0", ] -test = [ - "opentelemetry-instrumentation-requests[instruments]", - "httpretty ~= 1.0", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] requests = "opentelemetry.instrumentation.requests:RequestsInstrumentor" 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 4c198596a2..2052fe47cd 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, @@ -105,7 +107,7 @@ _excluded_urls_from_env = get_excluded_urls("REQUESTS") _RequestHookT = Optional[Callable[[Span, PreparedRequest], None]] -_ResponseHookT = Optional[Callable[[Span, PreparedRequest], None]] +_ResponseHookT = Optional[Callable[[Span, PreparedRequest, Response], None]] # pylint: disable=unused-argument @@ -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 @@ -174,14 +176,14 @@ def get_or_create_headers(): 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, @@ -191,11 +193,11 @@ def get_or_create_headers(): _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 @@ -284,16 +286,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 +349,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): 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/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt new file mode 100644 index 0000000000..be34594506 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt @@ -0,0 +1,24 @@ +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +Deprecated==1.2.14 +httpretty==1.1.4 +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.9.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-requests 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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-sqlalchemy/pyproject.toml index 1c63d671b7..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", ] @@ -35,11 +35,6 @@ dependencies = [ instruments = [ "sqlalchemy", ] -test = [ - "opentelemetry-instrumentation-sqlalchemy[instruments]", - "opentelemetry-sdk ~= 1.12", - "pytest", -] [project.entry-points.opentelemetry_instrumentor] sqlalchemy = "opentelemetry.instrumentation.sqlalchemy:SQLAlchemyInstrumentor" 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-sqlalchemy/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt new file mode 100644 index 0000000000..26fd283824 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +cffi==1.15.1 +Deprecated==1.2.14 +greenlet==0.4.13 +hpy==0.0.4.dev179+g9b5d200 +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 +readline==6.2.4.1 +SQLAlchemy==1.1.18 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-sqlalchemy diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt new file mode 100644 index 0000000000..bfb9dac972 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt @@ -0,0 +1,20 @@ +aiosqlite==0.20.0 +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +greenlet==3.0.3 +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 +SQLAlchemy==1.4.51 +tomli==2.0.1 +typing_extensions==4.10.0 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-sqlalchemy 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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml index 8b2f2a7014..69805b660c 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-starlette/pyproject.toml @@ -25,22 +25,16 @@ 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] instruments = [ "starlette ~= 0.13.0", ] -test = [ - "opentelemetry-instrumentation-starlette[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "requests ~= 2.23", # needed for testclient - "httpx ~= 0.22", # needed for testclient -] [project.entry-points.opentelemetry_instrumentor] starlette = "opentelemetry.instrumentation.starlette:StarletteInstrumentor" 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-starlette/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt new file mode 100644 index 0000000000..1cd21039a7 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt @@ -0,0 +1,31 @@ +anyio==4.3.0 +asgiref==3.7.2 +attrs==23.2.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +Deprecated==1.2.14 +exceptiongroup==1.2.0 +h11==0.14.0 +httpcore==1.0.4 +httpx==0.27.0 +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 +sniffio==1.3.0 +starlette==0.13.8 +tomli==2.0.1 +typing_extensions==4.9.0 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-asgi +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-starlette 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/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..1ef7dad2c5 --- /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 The OpenTelemetry Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT 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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml index 54706b42f2..ea1c48f011 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-tornado/pyproject.toml @@ -24,20 +24,15 @@ 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] instruments = [ "tornado >= 5.1.1", ] -test = [ - "opentelemetry-instrumentation-tornado[instruments]", - "opentelemetry-test-utils == 0.45b0.dev", - "http-server-mock" -] [project.entry-points.opentelemetry_instrumentor] tornado = "opentelemetry.instrumentation.tornado:TornadoInstrumentor" 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 dfa4b217df..5a39538837 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -296,7 +296,7 @@ def _create_server_histograms(meter) -> Dict[str, Histogram]: MetricInstruments.HTTP_SERVER_DURATION: meter.create_histogram( name=MetricInstruments.HTTP_SERVER_DURATION, unit="ms", - description="measures the duration outbound HTTP requests", + description="Duration of HTTP client requests.", ), MetricInstruments.HTTP_SERVER_REQUEST_SIZE: meter.create_histogram( name=MetricInstruments.HTTP_SERVER_REQUEST_SIZE, 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-tornado/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt new file mode 100644 index 0000000000..9f637278fd --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt @@ -0,0 +1,32 @@ +asgiref==3.7.2 +attrs==23.2.0 +blinker==1.7.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +click==8.1.7 +Deprecated==1.2.14 +Flask==3.0.2 +http_server_mock==1.7 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +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 +tornado==6.4 +typing_extensions==4.9.0 +urllib3==2.2.1 +Werkzeug==3.0.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-tornado diff --git a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py index 0baaa348ab..01cdddceed 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py @@ -528,7 +528,7 @@ def index(): class TestTornadoInstrumentationWithXHeaders(TornadoTest): - def get_httpserver_options(self): + def get_httpserver_options(self): # pylint: disable=no-self-use return {"xheaders": True} def test_xheaders(self): diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/README.rst b/instrumentation/opentelemetry-instrumentation-tortoiseorm/README.rst index e845fbf84d..22d6c01731 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/README.rst +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/README.rst @@ -19,5 +19,5 @@ References ---------- * `OpenTelemetry Project `_ -* `Tortoise ORM `_ +* `Tortoise ORM `_ * `OpenTelemetry Python Examples `_ 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/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/pyproject.toml b/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml index 3fe6d272cb..1011912a53 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-urllib/pyproject.toml @@ -25,17 +25,13 @@ 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] instruments = [] -test = [ - "httpretty ~= 1.0", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] urllib = "opentelemetry.instrumentation.urllib:URLLibInstrumentor" 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-urllib/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt new file mode 100644 index 0000000000..cdb10df7e9 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt @@ -0,0 +1,19 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +httpretty==1.1.4 +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 util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-urllib diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml b/instrumentation/opentelemetry-instrumentation-urllib3/pyproject.toml index fbd27f7bd8..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", ] @@ -35,11 +35,6 @@ dependencies = [ instruments = [ "urllib3 >= 1.0.0, < 3.0.0", ] -test = [ - "opentelemetry-instrumentation-urllib3[instruments]", - "httpretty ~= 1.0", - "opentelemetry-test-utils == 0.45b0.dev", -] [project.entry-points.opentelemetry_instrumentor] urllib3 = "opentelemetry.instrumentation.urllib3:URLLib3Instrumentor" 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-urllib3/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-0.txt new file mode 100644 index 0000000000..730ef16977 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-0.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +httpretty==1.1.4 +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 +urllib3==1.26.18 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-urllib3 diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt new file mode 100644 index 0000000000..1f10502f57 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt @@ -0,0 +1,20 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +httpretty==1.1.4 +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 +urllib3==2.2.1 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-urllib3 diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml b/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml index bb1b6ef286..e3e8bca651 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-wsgi/pyproject.toml @@ -25,16 +25,13 @@ 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] instruments = [] -test = [ - "opentelemetry-test-utils == 0.45b0.dev", -] [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-wsgi" 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 87c73cc737..0a873d0fc3 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -213,10 +213,34 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he from timeit import default_timer 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 @@ -228,6 +252,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, @@ -239,26 +264,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( @@ -296,53 +301,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 @@ -358,7 +394,6 @@ def collect_custom_request_headers_attributes(environ): OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS ) ) - headers = { key[_CARRIER_KEY_PREFIX_LEN:].replace("_", "-"): val for key, val in environ.items() @@ -387,7 +422,12 @@ def collect_custom_response_headers_attributes(response_headers): ) response_headers_dict = {} if response_headers: - response_headers_dict = dict(response_headers) + for key, val in response_headers: + key = key.lower() + if key in response_headers_dict: + response_headers_dict[key] += "," + val + else: + response_headers_dict[key] = val return sanitize.sanitize_header_values( response_headers_dict, @@ -406,46 +446,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): @@ -460,6 +510,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}" @@ -491,42 +543,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="measures the duration of the inbound HTTP request", + 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 @@ -547,11 +623,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, @@ -580,20 +658,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/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/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt new file mode 100644 index 0000000000..a4910352ed --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-wsgi/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 util/opentelemetry-util-http +-e instrumentation/opentelemetry-instrumentation-wsgi diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index d71e584ca8..985fbe0571 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, @@ -115,17 +126,70 @@ def wsgi_with_custom_response_headers(environ, start_response): return [b"*"] -_expected_metric_names = [ +def wsgi_with_repeat_custom_response_headers(environ, start_response): + assert isinstance(environ, dict) + start_response( + "200 OK", + [ + ("my-custom-header", "my-custom-value-1"), + ("my-custom-header", "my-custom-value-2"), + ], + ) + return [b"*"] + + +_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, @@ -134,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: @@ -159,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, @@ -167,10 +234,27 @@ 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, } + 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): @@ -178,6 +262,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", @@ -271,7 +365,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: @@ -282,7 +407,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) @@ -291,7 +455,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( @@ -337,34 +501,95 @@ 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 validate_url(self, expected_url, raw=False, has_host=True): + 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", + }, + ) + + 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, @@ -373,18 +598,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"] @@ -426,10 +701,10 @@ 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): @@ -437,29 +712,58 @@ def test_request_attributes_with_full_request_uri(self): self.environ["REQUEST_METHOD"] = "CONNECT" self.environ[ "REQUEST_URI" - ] = "127.0.0.1:8080" # Might happen in a CONNECT request - expected = { + ] = "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" @@ -711,6 +1015,26 @@ def test_custom_response_headers_not_added_in_internal_span(self): for key, _ in not_expected.items(): self.assertNotIn(key, span.attributes) + @mock.patch.dict( + "os.environ", + { + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE: "my-custom-header", + }, + ) + def test_repeat_custom_response_headers_added_in_server_span(self): + app = otel_wsgi.OpenTelemetryMiddleware( + wsgi_with_repeat_custom_response_headers + ) + response = app(self.environ, self.start_response) + self.iterate_response(response) + span = self.memory_exporter.get_finished_spans()[0] + expected = { + "http.response.header.my_custom_header": ( + "my-custom-value-1,my-custom-value-2", + ), + } + self.assertSpanHasAttributes(span, expected) + if __name__ == "__main__": unittest.main() diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index 2ed7ccec87..7e4afad6f7 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -28,58 +28,56 @@ 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.optional-dependencies] -test = [] - [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-contrib-instrumentations" 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/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..31c2486acc 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,117 @@ # 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, + # TODO: Support opt-in for scheme in new semconv + # 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 -def _filter_duration_attrs(attrs, sem_conv_opt_in_mode): + +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 + + @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 +166,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 +215,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) @@ -105,36 +239,30 @@ def _set_http_scheme(result, scheme, 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 +272,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/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/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..f92a5db8b1 --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/CHANGELOG.md @@ -0,0 +1,15 @@ +# 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 + +- Change meta data service timeout to 200ms + ([#2387](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2387)) + +## Version 0.1.2 (2024-01-25) + +- Initial CHANGELOG.md entry 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/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..da4c6563a5 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 @@ -71,10 +71,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-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/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/scripts/prepare_release.sh b/scripts/prepare_release.sh index a0bb15f216..66ed3c593e 100755 --- a/scripts/prepare_release.sh +++ b/scripts/prepare_release.sh @@ -1,5 +1,6 @@ #!/bin/bash -# +set -e + # This script: # 1. parses the version number from the branch name # 2. updates version.py files to match that version 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 820ac93816..bee544cb70 100644 --- a/tox.ini +++ b/tox.ini @@ -11,8 +11,8 @@ envlist = pypy3-test-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 ; opentelemetry-distro py3{8,9,10,11}-test-distro @@ -27,7 +27,7 @@ envlist = pypy3-test-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 ; opentelemetry-instrumentation-aiopg @@ -44,7 +44,7 @@ envlist = ; pypy3-test-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 @@ -52,10 +52,18 @@ envlist = ; Only officially supported Python versions are tested for each Django ; major release. Updated list can be found at: ; https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: django~=2.0 + ; 1: django~=3.0 + ; 2: django>=4.0b1,<5.0 backports.zoneinfo==0.2.1 + ; 3: django>=4.0b1,<5.0 + py3{8,9}-test-instrumentation-django-0 + py3{8,9}-test-instrumentation-django-1 py3{8,9}-test-instrumentation-django-2 - py3{8,9,10,11}-test-instrumentation-django-3 - py3{8,9,10,11}-test-instrumentation-django-4 - pypy3-test-instrumentation-django-{2,3} + py3{10,11}-test-instrumentation-django-1 + py3{10,11}-test-instrumentation-django-3 + pypy3-test-instrumentation-django-{0,1} ; opentelemetry-instrumentation-dbapi py3{8,9,10,11}-test-instrumentation-dbapi @@ -67,33 +75,49 @@ envlist = ; pypy3-test-instrumentation-boto ; opentelemetry-instrumentation-elasticsearch - py3{8,9,10,11}-test-instrumentation-elasticsearch-{2,6} - pypy3-test-instrumentation-elasticsearch-{2,6} - py3{8,9}-test-instrumentation-elasticsearch-5 - pypy3-test-instrumentation-elasticsearch-5 + ; 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: + ; 6: elasticsearch-dsl>=6.0,<7.0 elasticsearch>=6.0,<7.0 + py3{8,9,10,11}-test-instrumentation-elasticsearch-6 + pypy3-test-instrumentation-elasticsearch-6 ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 - py3{8,9}-test-instrumentation-falcon-1 - py3{8,9,10,11}-test-instrumentation-falcon-{2,3} - pypy3-test-instrumentation-falcon-{1,2,3} + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: falcon ==1.4.1 + ; 1: falcon >=2.0.0,<3.0.0 + ; 2: falcon >=3.0.0,<4.0.0 + py3{8,9}-test-instrumentation-falcon-0 + py3{8,9,10,11}-test-instrumentation-falcon-{1,2} + pypy3-test-instrumentation-falcon-{0,1,2} ; opentelemetry-instrumentation-fastapi py3{8,9,10,11}-test-instrumentation-fastapi pypy3-test-instrumentation-fastapi ; opentelemetry-instrumentation-flask - py3{8,9,10,11}-test-instrumentation-flask-{213,220} - py3{8,9,10,11}-test-instrumentation-flask-{300} - pypy3-test-instrumentation-flask-{213,220} + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: Flask ==2.1.3 Werkzeug <3.0.0 + ; 1: Flask ==2.2.0 Werkzeug <3.0.0 + ; 2: Flask >=3.0.0 Werkzeug >=3.0.0 + 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} ; opentelemetry-instrumentation-urllib py3{8,9,10,11}-test-instrumentation-urllib pypy3-test-instrumentation-urllib ; opentelemetry-instrumentation-urllib3 - py3{8,9,10,11}-test-instrumentation-urllib3v-{1,2} - pypy3-test-instrumentation-urllib3v-{1,2} + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: urllib3 >=1.0.0,<2.0.0 + ; 1: urllib3 >=2.0.0,<3.0.0 + py3{8,9,10,11}-test-instrumentation-urllib3-{0,1} + pypy3-test-instrumentation-urllib3-{0,1} ; opentelemetry-instrumentation-requests py3{8,9,10,11}-test-instrumentation-requests @@ -116,7 +140,7 @@ envlist = pypy3-test-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 ; opentelemetry-instrumentation-mysql @@ -132,12 +156,19 @@ envlist = ; ext-psycopg2 intentionally excluded from pypy3 ; opentelemetry-instrumentation-psycopg - py3{7,8,9,10,11}-test-instrumentation-psycopg + py3{8,9,10,11}-test-instrumentation-psycopg pypy3-test-instrumentation-psycopg ; opentelemetry-instrumentation-pymemcache - py3{8,9,10,11}-test-instrumentation-pymemcache-{135,200,300,342,400} - pypy3-test-instrumentation-pymemcache-{135,200,300,342,400} + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: pymemcache ==1.3.5 + ; 1: pymemcache >2.0.0,<3.0.0 + ; 2: pymemcache >3.0.0,<3.4.2 + ; 3: pymemcache ==3.4.2 + ; 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} ; opentelemetry-instrumentation-pymongo py3{8,9,10,11}-test-instrumentation-pymongo @@ -172,8 +203,12 @@ envlist = pypy3-test-instrumentation-grpc ; opentelemetry-instrumentation-sqlalchemy - py3{8,9,10,11}-test-instrumentation-sqlalchemy-{14} - pypy3-test-instrumentation-sqlalchemy-{11,14} + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: sqlalchemy>=1.1,<1.2 + ; 1: sqlalchemy~=1.4 aiosqlite + py3{8,9,10,11}-test-instrumentation-sqlalchemy-{1} + pypy3-test-instrumentation-sqlalchemy-{0,1} ; opentelemetry-instrumentation-redis py3{8,9,10,11}-test-instrumentation-redis @@ -191,9 +226,13 @@ envlist = py3{8}-test-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 + ; opentelemetry-instrumentation-threading + py3{8,9,10,11}-test-instrumentation-threading + pypy3-test-instrumentation-threading + ; opentelemetry-instrumentation-tornado py3{8,9,10,11}-test-instrumentation-tornado pypy3-test-instrumentation-tornado @@ -203,8 +242,8 @@ envlist = pypy3-test-instrumentation-tortoiseorm ; opentelemetry-instrumentation-httpx - py3{8,9,10,11}-test-instrumentation-httpx-{18,21} - pypy3-test-instrumentation-httpx-{18,21} + py3{8,9,10,11}-test-instrumentation-httpx-{0,1} + pypy3-test-instrumentation-httpx-{0,1} ; opentelemetry-util-http py3{8,9,10,11}-test-util-http @@ -219,12 +258,21 @@ envlist = pypy3-test-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} ; opentelemetry-instrumentation-aio-pika - py3{8,9,10,11}-test-instrumentation-aio-pika-{8,9} - pypy3-test-instrumentation-aio-pika-{8,9} + ; 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} ; opentelemetry-instrumentation-kafka-python py3{8,9,10,11}-test-instrumentation-kafka-python @@ -255,49 +303,7 @@ deps = test: pytest-benchmark coverage: pytest coverage: pytest-cov - django-2: django~=2.0 - django-3: django~=3.0 - django-4: django>=4.0b1,<5.0 - elasticsearch-2: elasticsearch-dsl>=2.0,<3.0 - elasticsearch-2: elasticsearch>=2.0,<3.0 - elasticsearch-5: elasticsearch-dsl>=5.0,<6.0 - elasticsearch-5: elasticsearch>=5.0,<6.0 - elasticsearch-6: elasticsearch-dsl>=6.0,<7.0 - elasticsearch-6: elasticsearch>=6.0,<7.0 - ; FIXME: Elasticsearch >=7 causes CI workflow tests to hang, see open-telemetry/opentelemetry-python-contrib#620 - ; elasticsearch-7: elasticsearch-dsl>=7.0,<8.0 - ; elasticsearch-7: elasticsearch>=7.0,<8.0 - ; elasticsearch-8: elasticsearch-dsl>=8.0,<9.0 - ; elasticsearch-8: elasticsearch>=8.0,<9.0 - falcon-1: falcon ==1.4.1 - falcon-2: falcon >=2.0.0,<3.0.0 - falcon-3: falcon >=3.0.0,<4.0.0 - flask-213: Flask ==2.1.3 - flask-213: Werkzeug <3.0.0 - flask-220: Flask ==2.2.0 - flask-220: Werkzeug <3.0.0 - flask-300: Flask >=3.0.0 - flask-300: Werkzeug >=3.0.0 grpc: pytest-asyncio - sqlalchemy-11: sqlalchemy>=1.1,<1.2 - sqlalchemy-14: aiosqlite - sqlalchemy-14: sqlalchemy~=1.4 - sio-pika-0: pika>=0.12.0,<1.0.0 - sio-pika-1: pika>=1.0.0 - aio-pika-7: aio_pika~=7.2.0 - aio-pika-8: aio_pika>=8.0.0,<9.0.0 - aio-pika-9: aio_pika>=9.0.0,<10.0.0 - pymemcache-135: pymemcache ==1.3.5 - pymemcache-200: pymemcache >2.0.0,<3.0.0 - pymemcache-300: pymemcache >3.0.0,<3.4.2 - pymemcache-342: pymemcache ==3.4.2 - pymemcache-400: pymemcache ==4.0.0 - httpx-18: httpx>=0.18.0,<0.19.0 - httpx-18: respx~=0.17.0 - httpx-21: httpx>=0.19.0 - httpx-21: respx~=0.20.1 - urllib3v-1: urllib3 >=1.0.0,<2.0.0 - urllib3v-2: urllib3 >=2.0.0,<3.0.0 ; FIXME: add coverage testing ; FIXME: add mypy testing @@ -308,193 +314,222 @@ setenv = CORE_REPO_SHA={env:CORE_REPO_SHA:main} CORE_REPO=git+https://github.com/open-telemetry/opentelemetry-python.git@{env:CORE_REPO_SHA} -changedir = - test-distro: opentelemetry-distro/tests - test-opentelemetry-instrumentation: opentelemetry-instrumentation/tests - test-instrumentation-aiohttp-client: instrumentation/opentelemetry-instrumentation-aiohttp-client/tests - test-instrumentation-aiohttp-server: instrumentation/opentelemetry-instrumentation-aiohttp-server/tests - test-instrumentation-aiopg: instrumentation/opentelemetry-instrumentation-aiopg/tests - test-instrumentation-asgi: instrumentation/opentelemetry-instrumentation-asgi/tests - test-instrumentation-asyncpg: instrumentation/opentelemetry-instrumentation-asyncpg/tests - test-instrumentation-aws-lambda: instrumentation/opentelemetry-instrumentation-aws-lambda/tests - test-instrumentation-boto: instrumentation/opentelemetry-instrumentation-boto/tests - test-instrumentation-botocore: instrumentation/opentelemetry-instrumentation-botocore/tests - test-instrumentation-boto3sqs: instrumentation/opentelemetry-instrumentation-boto3sqs/tests - test-instrumentation-cassandra: instrumentation/opentelemetry-instrumentation-cassandra/tests - test-instrumentation-celery: instrumentation/opentelemetry-instrumentation-celery/tests - test-instrumentation-dbapi: instrumentation/opentelemetry-instrumentation-dbapi/tests - test-instrumentation-django-{1,2,3,4}: instrumentation/opentelemetry-instrumentation-django/tests - test-instrumentation-elasticsearch-{2,5,6}: instrumentation/opentelemetry-instrumentation-elasticsearch/tests - test-instrumentation-falcon-{1,2,3}: instrumentation/opentelemetry-instrumentation-falcon/tests - test-instrumentation-fastapi: instrumentation/opentelemetry-instrumentation-fastapi/tests - test-instrumentation-flask-{213,220,300}: instrumentation/opentelemetry-instrumentation-flask/tests - test-instrumentation-urllib: instrumentation/opentelemetry-instrumentation-urllib/tests - test-instrumentation-urllib3v-{1,2}: instrumentation/opentelemetry-instrumentation-urllib3/tests - test-instrumentation-grpc: instrumentation/opentelemetry-instrumentation-grpc/tests - test-instrumentation-jinja2: instrumentation/opentelemetry-instrumentation-jinja2/tests - test-instrumentation-kafka-python: instrumentation/opentelemetry-instrumentation-kafka-python/tests - test-instrumentation-confluent-kafka: instrumentation/opentelemetry-instrumentation-confluent-kafka/tests - test-instrumentation-logging: instrumentation/opentelemetry-instrumentation-logging/tests - test-instrumentation-mysql: instrumentation/opentelemetry-instrumentation-mysql/tests - test-instrumentation-mysqlclient: instrumentation/opentelemetry-instrumentation-mysqlclient/tests - test-instrumentation-sio-pika-{0,1}: instrumentation/opentelemetry-instrumentation-pika/tests - test-instrumentation-aio-pika-{8,9}: instrumentation/opentelemetry-instrumentation-aio-pika/tests - test-instrumentation-psycopg: instrumentation/opentelemetry-instrumentation-psycopg/tests - test-instrumentation-psycopg2: instrumentation/opentelemetry-instrumentation-psycopg2/tests - test-instrumentation-pymemcache-{135,200,300,342,400}: instrumentation/opentelemetry-instrumentation-pymemcache/tests - test-instrumentation-pymongo: instrumentation/opentelemetry-instrumentation-pymongo/tests - test-instrumentation-pymysql: instrumentation/opentelemetry-instrumentation-pymysql/tests - test-instrumentation-pyramid: instrumentation/opentelemetry-instrumentation-pyramid/tests - test-instrumentation-redis: instrumentation/opentelemetry-instrumentation-redis/tests - test-instrumentation-remoulade: instrumentation/opentelemetry-instrumentation-remoulade/tests - test-instrumentation-requests: instrumentation/opentelemetry-instrumentation-requests/tests - test-instrumentation-sklearn: instrumentation/opentelemetry-instrumentation-sklearn/tests - test-instrumentation-sqlalchemy-{11,14}: instrumentation/opentelemetry-instrumentation-sqlalchemy/tests - test-instrumentation-sqlite3: instrumentation/opentelemetry-instrumentation-sqlite3/tests - test-instrumentation-starlette: instrumentation/opentelemetry-instrumentation-starlette/tests - test-instrumentation-system-metrics: instrumentation/opentelemetry-instrumentation-system-metrics/tests - test-instrumentation-tornado: instrumentation/opentelemetry-instrumentation-tornado/tests - test-instrumentation-tortoiseorm: instrumentation/opentelemetry-instrumentation-tortoiseorm/tests - test-instrumentation-wsgi: instrumentation/opentelemetry-instrumentation-wsgi/tests - test-instrumentation-httpx-{18,21}: instrumentation/opentelemetry-instrumentation-httpx/tests - test-instrumentation-asyncio: instrumentation/opentelemetry-instrumentation-asyncio/tests - test-util-http: util/opentelemetry-util-http/tests - test-sdkextension-aws: sdk-extension/opentelemetry-sdk-extension-aws/tests - test-resource-detector-container: resource/opentelemetry-resource-detector-container/tests - test-propagator-aws: propagator/opentelemetry-propagator-aws-xray/tests - test-propagator-ot-trace: propagator/opentelemetry-propagator-ot-trace/tests - test-exporter-richconsole: exporter/opentelemetry-exporter-richconsole/tests - test-exporter-prometheus-remote-write: exporter/opentelemetry-exporter-prometheus-remote-write/tests - 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 opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + test: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + test: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + test: pip install opentelemetry-test-utils@{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 -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt + + distro: pip install -r {toxinidir}/opentelemetry-distro/test-requirements.txt + + asgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt + + 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 - celery: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] + 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 - sio-pika-{0,1}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] + 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 - aio-pika-{8,9}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] + kafka-python: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt - kafka-python: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] + confluent-kafka: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt - confluent-kafka: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] + grpc: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt - grpc: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] + wsgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt - falcon-{1,2,3},flask-{213,220,300},django-{1,2,3,4},pyramid,tornado,starlette,fastapi,aiohttp,asgi,httpx-{18,21},requests,urllib,urllib3v-{1,2},wsgi: pip install {toxinidir}/util/opentelemetry-util-http - wsgi,falcon-{1,2,3},flask-{213,220,300},django-{1,2,3,4},pyramid: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] - asgi,django-{3,4},starlette,fastapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] + asyncpg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt - asyncpg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] + aws-lambda: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt - aws-lambda: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] + boto: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt - boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] + boto3sqs: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt - boto3sqs: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] + 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 - falcon-{1,2,3}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] + 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 - flask-{213,220,300}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] + urllib: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt - urllib: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] + 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 - urllib3v-{1,2}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] + botocore: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt - botocore: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] + cassandra: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt - cassandra: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] + dbapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt - dbapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] + 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 + py3{10,11}-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt + 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 - django-{1,2,3,4}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] + fastapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt - fastapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] + mysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt - mysql: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] + mysqlclient: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - mysqlclient: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] + 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 - pymemcache-{135,200,300,342,400}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] + pymongo: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt - pymongo: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] + 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 - psycopg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg[test] + psycopg2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt - psycopg2: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] + pymysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt - pymysql: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] + pyramid: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt - pyramid: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] + sqlite3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt - sqlite3: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] + redis: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt - redis: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] + remoulade: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt - remoulade: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] + requests: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt - requests: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] + starlette: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt - starlette: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] + system-metrics: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt - system-metrics: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] + threading: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt - tornado: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] + tornado: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt - tortoiseorm: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] + tortoiseorm: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt - jinja2: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] + jinja2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt - logging: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] + logging: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt - aio-pika-{8,9}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] + aio-pika-{0,1,2}: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - aiohttp-client: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] + aiohttp-client: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt - aiohttp-server: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] + aiohttp-server: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt - aiopg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] + aiopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt - richconsole: pip install flaky {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] + richconsole: pip install -r {toxinidir}/exporter/opentelemetry-exporter-richconsole/test-requirements.txt - prometheus: pip install {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write[test] + prometheus: pip install -r {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt - sklearn: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] + sklearn: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt - sqlalchemy-{11,14}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] + 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 - elasticsearch-{2,5,6}: pip install {toxinidir}/opentelemetry-instrumentation[test] {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] + elasticsearch-6: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt - asyncio: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] + asyncio: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt - httpx-{18,21}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] + ; 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-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] + sdk-extension-aws: pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt - resource-detector-container: pip install {toxinidir}/resource/opentelemetry-resource-detector-container[test] + resource-detector-container: pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/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-ot-trace: pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt - propagator-aws-xray: pip install requests {toxinidir}/propagator/opentelemetry-propagator-aws-xray[test] + propagator-aws-xray: pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt ; we have to install packages in editable mode. coverage: python {toxinidir}/scripts/eachdist.py install --editable commands = - test: pytest {posargs} + test-distro: pytest {toxinidir}/opentelemetry-distro/tests {posargs} + test-opentelemetry-instrumentation: pytest {toxinidir}/opentelemetry-instrumentation/tests {posargs} + test-instrumentation-aiohttp-client: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests {posargs} + test-instrumentation-aiohttp-server: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests {posargs} + test-instrumentation-aiopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/tests {posargs} + test-instrumentation-asgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/tests {posargs} + test-instrumentation-asyncpg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/tests {posargs} + test-instrumentation-aws-lambda: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/tests {posargs} + test-instrumentation-boto: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/tests {posargs} + test-instrumentation-botocore: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/tests {posargs} + test-instrumentation-boto3sqs: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/tests {posargs} + test-instrumentation-cassandra: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/tests {posargs} + test-instrumentation-celery: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/tests {posargs} + test-instrumentation-dbapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/tests {posargs} + test-instrumentation-django: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-django/tests {posargs} + test-instrumentation-elasticsearch: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/tests {posargs} + test-instrumentation-falcon: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/tests {posargs} + test-instrumentation-fastapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/tests {posargs} + test-instrumentation-flask: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/tests {posargs} + test-instrumentation-urllib: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/tests {posargs} + test-instrumentation-urllib3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/tests {posargs} + test-instrumentation-grpc: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/tests {posargs} + test-instrumentation-jinja2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/tests {posargs} + test-instrumentation-kafka-python: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/tests {posargs} + test-instrumentation-confluent-kafka: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/tests {posargs} + test-instrumentation-logging: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/tests {posargs} + test-instrumentation-mysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/tests {posargs} + test-instrumentation-mysqlclient: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/tests {posargs} + test-instrumentation-sio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/tests {posargs} + test-instrumentation-aio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/tests {posargs} + test-instrumentation-psycopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/tests {posargs} + test-instrumentation-psycopg2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/tests {posargs} + test-instrumentation-pymemcache: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/tests {posargs} + test-instrumentation-pymongo: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/tests {posargs} + test-instrumentation-pymysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/tests {posargs} + test-instrumentation-pyramid: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/tests {posargs} + test-instrumentation-redis: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/tests {posargs} + test-instrumentation-remoulade: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/tests {posargs} + test-instrumentation-requests: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/tests {posargs} + test-instrumentation-sklearn: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/tests {posargs} + test-instrumentation-sqlalchemy: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests {posargs} + test-instrumentation-sqlite3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/tests {posargs} + test-instrumentation-starlette: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/tests {posargs} + test-instrumentation-system-metrics: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/tests {posargs} + test-instrumentation-threading: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/tests {posargs} + test-instrumentation-tornado: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/tests {posargs} + test-instrumentation-tortoiseorm: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/tests {posargs} + test-instrumentation-wsgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/tests {posargs} + test-instrumentation-httpx: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/tests {posargs} + test-instrumentation-asyncio: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/tests {posargs} + test-util-http: pytest {toxinidir}/util/opentelemetry-util-http/tests {posargs} + test-sdk-extension-aws: pytest {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests {posargs} + 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} + test-propagator-ot-trace: pytest {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests {posargs} + test-exporter-richconsole: pytest {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests {posargs} + test-exporter-prometheus-remote-write: pytest {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests {posargs} coverage: {toxinidir}/scripts/coverage.sh [testenv:docs] @@ -536,63 +571,64 @@ commands_pre = 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] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] - 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] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] - ; 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] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] - 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] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[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 + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt + pip install -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt + ; pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt + 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 + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + 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 + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install # for your OS to install the required dependencies - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] - python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt + pip install -r {toxinidir}/exporter/opentelemetry-exporter-richconsole/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt # 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] + pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/test-requirements.txt + pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt + pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt + pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt + pip install -r {toxinidir}/opentelemetry-distro/test-requirements.txt commands = python scripts/eachdist.py lint --check-only @@ -600,30 +636,82 @@ commands = [testenv:docker-tests] basepython: python3 deps = - pip >= 20.3.3 - pytest - asyncpg==0.27.0 - docker-compose >= 1.25.2 - mysql-connector-python ~= 8.0 - pymongo >= 3.1, < 5.0 - PyMySQL ~= 0.10.1 + aiopg==1.4.0 + amqp==5.2.0 + asgiref==3.7.2 + async-timeout==4.0.3 + asyncpg==0.29.0 + attrs==23.2.0 + bcrypt==4.1.2 + billiard==4.2.0 + celery==5.3.6 + certifi==2024.2.2 + cffi==1.16.0 + chardet==3.0.4 + click==8.1.7 + click-didyoumean==0.3.0 + click-plugins==1.1.1 + click-repl==0.3.0 + cryptography==42.0.5 + Deprecated==1.2.14 + distro==1.9.0 + dnspython==2.6.1 + docker==5.0.3 + docker-compose==1.29.2 + dockerpty==0.4.1 + docopt==0.6.2 + exceptiongroup==1.2.0 + flaky==3.7.0 + greenlet==3.0.3 + grpcio==1.62.1 + idna==2.10 + importlib-metadata==6.11.0 + iniconfig==2.0.0 + jsonschema==3.2.0 + kombu==5.3.5 + mysql-connector-python==8.3.0 + mysqlclient==2.1.1 + opencensus-proto==0.1.0 + packaging==24.0 + paramiko==3.4.0 + pluggy==1.4.0 + prometheus_client==0.20.0 + prompt-toolkit==3.0.43 + protobuf==3.20.3 # prerequisite: install libpq-dev (debian) or postgresql-devel (rhel), postgresql (mac) # see https://www.psycopg.org/docs/install.html#build-prerequisites # you might have to install additional packages depending on your OS - psycopg ~= 3.1.17 - psycopg2 ~= 2.9.5 - aiopg >= 0.13.0, < 1.3.0 - sqlalchemy ~= 1.4 - redis ~= 4.3 - celery[pytest] >= 4.0, < 6.0 - protobuf~=3.13 - requests==2.25.0 + psycopg==3.1.18 + psycopg2==2.9.9 + psycopg2-binary==2.9.9 + pycparser==2.21 + pymongo==4.6.2 + PyMySQL==0.10.1 + PyNaCl==1.5.0 # prerequisite: install unixodbc - pyodbc~=4.0.30 - flaky==3.7.0 - remoulade>=0.50 - mysqlclient~=2.1.1 - pyyaml==5.3.1 + pyodbc==4.0.39 + pyrsistent==0.20.0 + pytest==8.0.2 + pytest-celery==0.0.0 + python-dateutil==2.9.0.post0 + python-dotenv==0.21.1 + pytz==2024.1 + PyYAML==5.3.1 + redis==5.0.1 + remoulade==3.2.0 + requests==2.25.0 + six==1.16.0 + SQLAlchemy==1.4.52 + texttable==1.7.0 + tomli==2.0.1 + typing_extensions==4.10.0 + tzdata==2024.1 + urllib3==1.26.18 + vine==5.1.0 + wcwidth==0.2.13 + websocket-client==0.59.0 + wrapt==1.16.0 + zipp==3.18.0 changedir = tests/opentelemetry-docker-tests/tests 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 523f9400b1..1f7ce98937 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"