diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000000..1e85aefda8 --- /dev/null +++ b/.codespellrc @@ -0,0 +1,4 @@ +[codespell] +# skipping auto generated folders +skip = ./.tox,./.mypy_cache,./docs/_build,./target,*/LICENSE,./venv +ignore-words-list = ot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3cbc0bc877..6804222fd4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,31 +6,30 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: 05d251c5d6baefe2f084e7361cb144c4fa10da96 + CORE_REPO_SHA: b3b0ba3a47dbdd844b524c46db22a60549364071 jobs: build: env: # We use these variables to convert between tox and GHA version literals - py36: 3.6 py37: 3.7 py38: 3.8 py39: 3.9 py310: "3.10" - pypy3: pypy3 + pypy3: "pypy3.7" RUN_MATRIX_COMBINATION: ${{ matrix.python-version }}-${{ matrix.package }}-${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false # ensures the entire test matrix is run, even if one permutation fails matrix: - python-version: [ py36, py37, py38, py39, py310, pypy3 ] + python-version: [ py37, py38, py39, py310, pypy3 ] package: ["instrumentation", "distro", "exporter", "sdkextension", "propagator"] os: [ ubuntu-20.04 ] steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} uses: actions/checkout@v2 - name: Set up Python ${{ env[matrix.python-version] }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ env[matrix.python-version] }} - name: Install tox @@ -42,7 +41,7 @@ jobs: path: | .tox ~/.cache/pip - key: v6-build-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} + key: v7-build-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} - name: run tox run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- --benchmark-json=${{ env.RUN_MATRIX_COMBINATION }}-benchmark.json # - name: Find and merge ${{ matrix.package }} benchmarks @@ -96,7 +95,7 @@ jobs: strategy: fail-fast: false matrix: - tox-environment: [ "docker-tests", "lint", "docs", "generate" ] + tox-environment: [ "docker-tests", "spellcheck", "lint", "docs", "generate" ] name: ${{ matrix.tox-environment }} runs-on: ubuntu-20.04 steps: @@ -118,7 +117,7 @@ jobs: path: | .tox ~/.cache/pip - key: v6-misc-tox-cache-${{ matrix.tox-environment }}-${{ hashFiles('tox.ini', 'dev-requirements.txt', 'gen-requirements.txt', 'docs-requirements.txt') }} + key: v7-misc-tox-cache-${{ matrix.tox-environment }}-${{ hashFiles('tox.ini', 'dev-requirements.txt', 'gen-requirements.txt', 'docs-requirements.txt') }} - name: run tox run: tox -e ${{ matrix.tox-environment }} - name: Ensure generated code is up to date diff --git a/CHANGELOG.md b/CHANGELOG.md index f1366aa535..1deb56d4b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,37 @@ 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](https://github.com/open-telemetry/opentelemetry-python/compare/v1.12.0rc2-0.32b0...HEAD) +## [Unreleased] + +### Fixed + +- `opentelemetry-instrumentation-boto3sqs` Make propagation compatible with other SQS instrumentations, add 'messaging.url' span attribute, and fix missing package dependencies. + ([#1234](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1234)) +- restoring metrics in django framework + ([#1208](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1208)) +- `opentelemetry-instrumentation-aiohttp-client` Fix producing additional spans with each newly created ClientSession +- ([#1246](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1246)) + +## [1.12.0-0.33b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0-0.33b0) - 2022-08-08 + - Adding multiple db connections support for django-instrumentation's sqlcommenter ([#1187](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1187)) +- SQLCommenter semicolon bug fix + ([#1200](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1200/files)) +- Adding sqlalchemy native tags in sqlalchemy commenter + ([#1206](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1206)) +- Add psycopg2 native tags to sqlcommenter + ([#1203](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1203)) ### Added - `opentelemetry-instrumentation-redis` add support to instrument RedisCluster clients ([#1177](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1177)) - `opentelemetry-instrumentation-sqlalchemy` Added span for the connection phase ([#1133](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1133)) -- `opentelemetry-instrumentation-tornado` Add metric instrumentation +- Add metric instrumentation in asgi + ([#1197](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1197)) +- Add metric instumentation for flask + ([#1186](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1186)) +- Add metric instrumentation for tornado ([#1252](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1252)) ## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-01 @@ -51,6 +73,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1127](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1127)) - Add metric instrumentation for WSGI ([#1128](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1128)) +- Add metric instrumentation for Urllib3 + ([#1198](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1198)) - `opentelemetry-instrumentation-aio-pika` added RabbitMQ aio-pika module instrumentation. ([#1095](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1095)) - `opentelemetry-instrumentation-requests` Restoring metrics in requests @@ -418,7 +442,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#567](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/567)) - `opentelemetry-instrumentation-grpc` Respect the suppress instrumentation in gRPC client instrumentor ([#559](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/559)) -- `opentelemetry-instrumentation-grpc` Fixed asynchonous unary call traces +- `opentelemetry-instrumentation-grpc` Fixed asynchronous unary call traces ([#536](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/536)) - `opentelemetry-sdk-extension-aws` Update AWS entry points to match spec ([#566](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/566)) @@ -714,7 +738,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#182](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/182)) - `opentelemetry-instrumentation-botocore` Botocore SpanKind as CLIENT and modify existing traced attributes ([#150](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/150)) -- `opentelemetry-instrumentation-dbapi` Update dbapi and its dependant instrumentations to follow semantic conventions +- `opentelemetry-instrumentation-dbapi` Update dbapi and its dependent instrumentations to follow semantic conventions ([#195](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/195)) - `opentelemetry-instrumentation-dbapi` Stop capturing query parameters by default ([#156](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/156)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed1de3f001..038ee1ab0b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,6 +44,7 @@ You can run: - `tox -e py37-test-flask` to e.g. run the Flask tests under a specific Python version - `tox -e lint` to run lint checks on all code +- `tox -e spellcheck` to run spell check on the code See [`tox.ini`](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/tox.ini) @@ -172,7 +173,7 @@ The continuation integration overrides that environment variable with as per the * docstrings should adhere to the [Google Python Style Guide](http://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) - as specified with the [napolean + as specified with the [napoleon extension](http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#google-vs-numpy) extension in [Sphinx](http://www.sphinx-doc.org/en/master/index.html). @@ -194,7 +195,7 @@ Below is a checklist of things to be mindful of when implementing a new instrume - 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 -- `url_filter` functonality +- `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 - `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 @@ -204,5 +205,5 @@ Below is a checklist of things to be mindful of when implementing a new instrume ## 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 memebers of the community are not so familiar with, so it is necessary to rely on the expertise of the original contributing parties. +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/_template/setup.cfg b/_template/setup.cfg index 62d74d1d9b..e34e383416 100644 --- a/_template/setup.cfg +++ b/_template/setup.cfg @@ -34,20 +34,19 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 + opentelemetry-api ~= 1.12 [options.extras_require] test = diff --git a/_template/version.py b/_template/version.py index 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/dev-requirements.txt b/dev-requirements.txt index 9ad388090d..7938bda186 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -15,3 +15,4 @@ grpcio-tools==1.29.0 mypy-protobuf>=1.23 protobuf~=3.13 markupsafe==2.0.1 +codespell==2.1.0 diff --git a/docs-requirements.txt b/docs-requirements.txt index 0e1bbfc7e0..e745057a7e 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -41,4 +41,6 @@ httpx>=0.18.0 # indirect dependency pins markupsafe==2.0.1 -itsdangerous==2.0.1 \ No newline at end of file +itsdangerous==2.0.1 + +docutils==0.16 \ No newline at end of file diff --git a/eachdist.ini b/eachdist.ini index e092e11eb7..090b4a372f 100644 --- a/eachdist.ini +++ b/eachdist.ini @@ -16,7 +16,7 @@ sortfirst= ext/* [stable] -version=1.12.0rc2 +version=1.12.0 packages= opentelemetry-sdk @@ -34,7 +34,7 @@ packages= opentelemetry-api [prerelease] -version=0.32b0 +version=0.33b0 packages= all diff --git a/exporter/opentelemetry-exporter-datadog/setup.cfg b/exporter/opentelemetry-exporter-datadog/setup.cfg index e0124554f4..3303c3e3df 100644 --- a/exporter/opentelemetry-exporter-datadog/setup.cfg +++ b/exporter/opentelemetry-exporter-datadog/setup.cfg @@ -28,21 +28,20 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = ddtrace>=0.34.0,<0.47.0 - opentelemetry-api ~= 1.3 - opentelemetry-sdk ~= 1.3 + opentelemetry-api ~= 1.12 + opentelemetry-sdk ~= 1.12 opentelemetry-semantic-conventions == 0.30b0 [options.packages.find] diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index c530f86e63..2913885cb4 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -127,7 +127,7 @@ def _translate_to_datadog(self, spans): # datadog Span is initialized with a reference to the tracer which is # used to record the span when it is finished. We can skip ignore this - # because we are not calling the finish method and explictly set the + # because we are not calling the finish method and explicitly set the # duration. tracer = None diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/spanprocessor.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/spanprocessor.py index d6581dd5cc..f8f9b50079 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/spanprocessor.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/spanprocessor.py @@ -16,13 +16,13 @@ import logging import threading import typing +from time import time_ns from opentelemetry.context import Context, attach, detach, set_value from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY from opentelemetry.sdk.trace import Span, SpanProcessor from opentelemetry.sdk.trace.export import SpanExporter from opentelemetry.trace import INVALID_TRACE_ID -from opentelemetry.util._time import _time_ns logger = logging.getLogger(__name__) @@ -127,10 +127,10 @@ def worker(self): # missing spans will be sent when calling flush break - # substract the duration of this export call to the next timeout - start = _time_ns() + # subtract the duration of this export call to the next timeout + start = time_ns() self.export() - end = _time_ns() + end = time_ns() duration = (end - start) / 1e9 timeout = self.schedule_delay_millis / 1e3 - duration diff --git a/exporter/opentelemetry-exporter-richconsole/setup.cfg b/exporter/opentelemetry-exporter-richconsole/setup.cfg index f5c8b5aba4..73a727aad7 100644 --- a/exporter/opentelemetry-exporter-richconsole/setup.cfg +++ b/exporter/opentelemetry-exporter-richconsole/setup.cfg @@ -28,22 +28,21 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = rich>=10.0.0 - opentelemetry-api ~= 1.3 - opentelemetry-sdk ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-sdk ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/README.md b/instrumentation/README.md index 71d79ea258..deeb3693f0 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -13,11 +13,11 @@ | [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 | No | [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No -| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | 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 | No | [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | No -| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0, < 3.0 | No +| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0, < 3.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 @@ -40,5 +40,5 @@ | [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | No | [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | No -| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 2.0.0 | No +| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 2.0.0 | Yes | [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/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-aio-pika/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-aio-pika/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/setup.cfg b/instrumentation/opentelemetry-instrumentation-aio-pika/setup.cfg index 65b327b925..9f9c0a5e56 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/setup.cfg @@ -28,14 +28,13 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: @@ -48,7 +47,7 @@ install_requires = test = pytest wrapt >= 1.0.0, < 2.0.0 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg index 0f88035410..11fc272f26 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg @@ -28,22 +28,21 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6.3 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.packages.find] @@ -54,4 +53,4 @@ test = [options.entry_points] opentelemetry_instrumentor = - aiohttp-client = opentelemetry.instrumentation.aiohttp_client:AioHttpClientInstrumentor \ No newline at end of file + aiohttp-client = opentelemetry.instrumentation.aiohttp_client:AioHttpClientInstrumentor diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py index e2eaaa7442..6323ad9bbe 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py @@ -59,7 +59,7 @@ def strip_query_params(url: yarl.URL) -> str: Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. .. code-block:: python @@ -262,7 +262,9 @@ def _instrument( url_filter: _UrlFilterT = None, request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, - trace_configs: typing.Optional[aiohttp.TraceConfig] = None, + trace_configs: typing.Optional[ + typing.Sequence[aiohttp.TraceConfig] + ] = None, ): """Enables tracing of all ClientSessions @@ -270,16 +272,15 @@ def _instrument( the session's trace_configs. """ - if trace_configs is None: - trace_configs = [] + trace_configs = trace_configs or () # pylint:disable=unused-argument def instrumented_init(wrapped, instance, args, kwargs): if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY): return wrapped(*args, **kwargs) - if kwargs.get("trace_configs"): - trace_configs.extend(kwargs.get("trace_configs")) + client_trace_configs = list(kwargs.get("trace_configs", ())) + client_trace_configs.extend(trace_configs) trace_config = create_trace_config( url_filter=url_filter, @@ -288,9 +289,9 @@ def instrumented_init(wrapped, instance, args, kwargs): tracer_provider=tracer_provider, ) trace_config._is_instrumented_by_opentelemetry = True - trace_configs.append(trace_config) + client_trace_configs.append(trace_config) - kwargs["trace_configs"] = trace_configs + kwargs["trace_configs"] = client_trace_configs return wrapped(*args, **kwargs) wrapt.wrap_function_wrapper( 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 0eb5bcc268..b0ae442a0c 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py index 92ca8f55be..524b93faeb 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py @@ -387,18 +387,35 @@ def test_instrument(self): self.assertEqual(200, span.attributes[SpanAttributes.HTTP_STATUS_CODE]) def test_instrument_with_custom_trace_config(self): + trace_config = aiohttp.TraceConfig() + AioHttpClientInstrumentor().uninstrument() - AioHttpClientInstrumentor().instrument( - trace_configs=[aiohttp_client.create_trace_config()] - ) + AioHttpClientInstrumentor().instrument(trace_configs=[trace_config]) - self.assert_spans(0) + async def make_request(server: aiohttp.test_utils.TestServer): + async with aiohttp.test_utils.TestClient(server) as client: + trace_configs = client.session._trace_configs + self.assertEqual(2, len(trace_configs)) + self.assertTrue(trace_config in trace_configs) + async with client as session: + await session.get(TestAioHttpClientInstrumentor.URL) - run_with_test_server( - self.get_default_request(), self.URL, self.default_handler - ) + run_with_test_server(make_request, self.URL, self.default_handler) + self.assert_spans(1) + + def test_every_request_by_new_session_creates_one_span(self): + async def make_request(server: aiohttp.test_utils.TestServer): + async with aiohttp.test_utils.TestClient(server) as client: + async with client as session: + await session.get(TestAioHttpClientInstrumentor.URL) - self.assert_spans(2) + for request_no in range(3): + self.memory_exporter.clear() + with self.subTest(request_no=request_no): + run_with_test_server( + make_request, self.URL, self.default_handler + ) + self.assert_spans(1) def test_instrument_with_existing_trace_config(self): trace_config = aiohttp.TraceConfig() @@ -446,7 +463,7 @@ async def uninstrument_request(server: aiohttp.test_utils.TestServer): run_with_test_server( self.get_default_request(), self.URL, self.default_handler ) - self.assert_spans(2) + self.assert_spans(1) def test_suppress_instrumentation(self): token = context.attach( diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg index 318059e460..69c19eff16 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg @@ -28,27 +28,26 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation-dbapi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation-dbapi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-test-utils == 0.33b0 + opentelemetry-semantic-conventions == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-asgi/LICENSE b/instrumentation/opentelemetry-instrumentation-asgi/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asgi/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-asgi/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-asgi/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asgi/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg b/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg index 55a8b56269..aec1f8d762 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg @@ -28,27 +28,26 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 asgiref ~= 3.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 d2e42450a0..21e8a189b5 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -71,8 +71,8 @@ async def hello(): Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. The server request hook takes in a server span and ASGI -scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method recieve is called. +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. The server request hook takes in a server span and ASGI +scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method receive is called. The client response hook is called with the internal span and an ASGI event which is sent as a dictionary for when the method send is called. .. code-block:: python @@ -149,6 +149,7 @@ def client_response_hook(span: Span, message: dict): import typing import urllib from functools import wraps +from timeit import default_timer from typing import Tuple from asgiref.compatibility import guarantee_single_callable @@ -162,6 +163,7 @@ def client_response_hook(span: Span, message: dict): _start_internal_or_server_span, http_status_to_status_code, ) +from opentelemetry.metrics import get_meter from opentelemetry.propagators.textmap import Getter, Setter from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import Span, set_span_in_context @@ -169,6 +171,8 @@ def client_response_hook(span: Span, message: dict): from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, + _parse_active_request_count_attrs, + _parse_duration_attrs, get_custom_headers, normalise_request_header_name, normalise_response_header_name, @@ -375,7 +379,7 @@ class OpenTelemetryMiddleware: server_request_hook: Optional callback which is called with the server span and ASGI scope object for every incoming request. client_request_hook: Optional callback which is called with the internal span and an ASGI - scope which is sent as a dictionary for when the method recieve is called. + scope which is sent as a dictionary for when the method receive is called. client_response_hook: Optional callback which is called with the internal span and an ASGI event which is sent as a dictionary for when the method send is called. tracer_provider: The optional tracer provider to use. If omitted @@ -391,9 +395,21 @@ def __init__( client_request_hook: _ClientRequestHookT = None, client_response_hook: _ClientResponseHookT = None, tracer_provider=None, + meter_provider=None, ): self.app = guarantee_single_callable(app) self.tracer = trace.get_tracer(__name__, __version__, tracer_provider) + self.meter = get_meter(__name__, __version__, meter_provider) + self.duration_histogram = self.meter.create_histogram( + name="http.server.duration", + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + self.active_requests_counter = self.meter.create_up_down_counter( + name="http.server.active_requests", + unit="requests", + description="measures the number of concurrent HTTP requests that are currently in-flight", + ) self.excluded_urls = excluded_urls self.default_span_details = ( default_span_details or get_default_span_details @@ -426,12 +442,17 @@ async def __call__(self, scope, receive, send): context_carrier=scope, context_getter=asgi_getter, ) - + attributes = collect_request_attributes(scope) + attributes.update(additional_attributes) + active_requests_count_attrs = _parse_active_request_count_attrs( + attributes + ) + duration_attrs = _parse_duration_attrs(attributes) + if scope["type"] == "http": + self.active_requests_counter.add(1, active_requests_count_attrs) try: with trace.use_span(span, end_on_exit=True) as current_span: if current_span.is_recording(): - attributes = collect_request_attributes(scope) - attributes.update(additional_attributes) for key, value in attributes.items(): current_span.set_attribute(key, value) @@ -454,10 +475,18 @@ async def __call__(self, scope, receive, send): span_name, scope, send, + duration_attrs, ) + start = default_timer() await self.app(scope, otel_receive, otel_send) finally: + if scope["type"] == "http": + duration = max(round((default_timer() - start) * 1000), 0) + self.duration_histogram.record(duration, duration_attrs) + self.active_requests_counter.add( + -1, active_requests_count_attrs + ) if token: context.detach(token) @@ -478,7 +507,9 @@ async def otel_receive(): return otel_receive - def _get_otel_send(self, server_span, server_span_name, scope, send): + def _get_otel_send( + self, server_span, server_span_name, scope, send, duration_attrs + ): @wraps(send) async def otel_send(message): with self.tracer.start_as_current_span( @@ -489,6 +520,9 @@ async def otel_send(message): if send_span.is_recording(): if message["type"] == "http.response.start": status_code = message["status"] + duration_attrs[ + SpanAttributes.HTTP_STATUS_CODE + ] = status_code set_status_code(server_span, status_code) set_status_code(send_span, status_code) elif message["type"] == "websocket.send": 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py index 3a1e8424a8..e6b75d7125 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py @@ -14,6 +14,7 @@ import sys import unittest +from timeit import default_timer from unittest import mock import opentelemetry.instrumentation.asgi as otel_asgi @@ -24,6 +25,10 @@ set_global_response_propagator, ) from opentelemetry.sdk import resources +from opentelemetry.sdk.metrics.export import ( + HistogramDataPoint, + NumberDataPoint, +) from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.asgitestutil import ( AsgiTestBase, @@ -34,8 +39,19 @@ from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, + _active_requests_count_attrs, + _duration_attrs, ) +_expected_metric_names = [ + "http.server.active_requests", + "http.server.duration", +] +_recommended_attrs = { + "http.server.active_requests": _active_requests_count_attrs, + "http.server.duration": _duration_attrs, +} + async def http_app(scope, receive, send): message = await receive() @@ -523,6 +539,101 @@ def update_expected_hook_results(expected): outputs, modifiers=[update_expected_hook_results] ) + def test_asgi_metrics(self): + app = otel_asgi.OpenTelemetryMiddleware(simple_asgi) + self.seed_app(app) + self.send_default_request() + self.seed_app(app) + self.send_default_request() + self.seed_app(app) + self.send_default_request() + 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) + 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_attrs[metric.name] + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_basic_metric_success(self): + app = otel_asgi.OpenTelemetryMiddleware(simple_asgi) + self.seed_app(app) + start = default_timer() + self.send_default_request() + duration = max(round((default_timer() - start) * 1000), 0) + expected_duration_attributes = { + "http.method": "GET", + "http.host": "127.0.0.1", + "http.scheme": "http", + "http.flavor": "1.0", + "net.host.port": 80, + "http.status_code": 200, + } + expected_requests_count_attributes = { + "http.method": "GET", + "http.host": "127.0.0.1", + "http.scheme": "http", + "http.flavor": "1.0", + } + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metrics in resource_metric.scope_metrics: + for metric in scope_metrics.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertDictEqual( + expected_duration_attributes, + dict(point.attributes), + ) + self.assertEqual(point.count, 1) + self.assertAlmostEqual( + duration, point.sum, delta=5 + ) + elif isinstance(point, NumberDataPoint): + self.assertDictEqual( + expected_requests_count_attributes, + dict(point.attributes), + ) + self.assertEqual(point.value, 0) + + def test_no_metric_for_websockets(self): + self.scope = { + "type": "websocket", + "http_version": "1.1", + "scheme": "ws", + "path": "/", + "query_string": b"", + "headers": [], + "client": ("127.0.0.1", 32767), + "server": ("127.0.0.1", 80), + } + app = otel_asgi.OpenTelemetryMiddleware(simple_asgi) + self.seed_app(app) + self.send_input({"type": "websocket.connect"}) + self.send_input({"type": "websocket.receive", "text": "ping"}) + self.send_input({"type": "websocket.disconnect"}) + self.get_all_output() + metrics_list = self.memory_metrics_reader.get_metrics_data() + self.assertEqual( + len(metrics_list.resource_metrics[0].scope_metrics), 0 + ) + class TestAsgiAttributes(unittest.TestCase): def setUp(self): diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/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-asyncpg/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-asyncpg/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg index 3bd41ec18c..49e3da4448 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/setup.cfg b/instrumentation/opentelemetry-instrumentation-aws-lambda/setup.cfg index fee5018e04..03a39fb1e4 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/setup.cfg @@ -28,23 +28,22 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-instrumentation == 0.32b0 + opentelemetry-instrumentation == 0.33b0 opentelemetry-propagator-aws-xray == 1.0.1 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-semantic-conventions == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 d791b2f17c..8467422fb9 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 @@ -14,7 +14,7 @@ """ The opentelemetry-instrumentation-aws-lambda package provides an `Instrumentor` -to traces calls whithin a Python AWS Lambda function. +to traces calls within a Python AWS Lambda function. Usage ----- 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-boto/setup.cfg b/instrumentation/opentelemetry-instrumentation-boto/setup.cfg index f5fa7ff568..02db129a4b 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-boto/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = moto~=2.0 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 markupsafe==2.0.1 [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py index 757ff95f03..b94cc744b3 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py @@ -86,7 +86,7 @@ def instrumentation_dependencies(self) -> Collection[str]: def _instrument(self, **kwargs): # AWSQueryConnection and AWSAuthConnection are two different classes # called by different services for connection. - # For exemple EC2 uses AWSQueryConnection and S3 uses + # For example EC2 uses AWSQueryConnection and S3 uses # AWSAuthConnection # pylint: disable=attribute-defined-outside-init 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-boto/tests/test_boto_instrumentation.py b/instrumentation/opentelemetry-instrumentation-boto/tests/test_boto_instrumentation.py index 32347e5693..70965f991a 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/tests/test_boto_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-boto/tests/test_boto_instrumentation.py @@ -147,7 +147,7 @@ def test_s3_client(self): self.assertEqual(span.attributes["aws.operation"], "head_bucket") self.assertEqual(span.name, "s3.command") - # Checking for resource incase of error + # Checking for resource in case of error try: s3.get_bucket("big_bucket") except Exception: # pylint: disable=broad-except diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE b/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/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-boto3sqs/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-boto3sqs/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/setup.cfg b/instrumentation/opentelemetry-instrumentation-boto3sqs/setup.cfg index 317bf2449e..6da1b06796 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/setup.cfg @@ -33,23 +33,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py index fa30816350..dacb931db6 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py @@ -29,7 +29,7 @@ Boto3SQSInstrumentor().instrument() """ import logging -from typing import Any, Collection, Dict, Generator, List, Optional +from typing import Any, Collection, Dict, Generator, List, Mapping, Optional import boto3 import botocore.client @@ -53,33 +53,31 @@ from .version import __version__ _logger = logging.getLogger(__name__) -# We use this prefix so we can request all instrumentation MessageAttributeNames with a wildcard, without harming -# existing filters -_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER: str = "otel." -_OTEL_IDENTIFIER_LENGTH = len(_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER) + +_IS_SQS_INSTRUMENTED_ATTRIBUTE = "_otel_boto3sqs_instrumented" class Boto3SQSGetter(Getter[CarrierT]): def get(self, carrier: CarrierT, key: str) -> Optional[List[str]]: - value = carrier.get(f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key}", {}) - if not value: + msg_attr = carrier.get(key) + if not isinstance(msg_attr, Mapping): + return None + + value = msg_attr.get("StringValue") + if value is None: return None - return [value.get("StringValue")] + + return [value] def keys(self, carrier: CarrierT) -> List[str]: - return [ - key[_OTEL_IDENTIFIER_LENGTH:] - if key.startswith(_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER) - else key - for key in carrier.keys() - ] + return list(carrier.keys()) class Boto3SQSSetter(Setter[CarrierT]): def set(self, carrier: CarrierT, key: str, value: str) -> None: # This is a limitation defined by AWS for SQS MessageAttributes size if len(carrier.items()) < 10: - carrier[f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key}"] = { + carrier[key] = { "StringValue": value, "DataType": "String", } @@ -145,6 +143,7 @@ def instrumentation_dependencies(self) -> Collection[str]: def _enrich_span( span: Span, queue_name: str, + queue_url: str, conversation_id: Optional[str] = None, operation: Optional[MessagingOperationValues] = None, message_id: Optional[str] = None, @@ -157,12 +156,12 @@ def _enrich_span( SpanAttributes.MESSAGING_DESTINATION_KIND, MessagingDestinationKindValues.QUEUE.value, ) + span.set_attribute(SpanAttributes.MESSAGING_URL, queue_url) + if operation: span.set_attribute( SpanAttributes.MESSAGING_OPERATION, operation.value ) - else: - span.set_attribute(SpanAttributes.MESSAGING_TEMP_DESTINATION, True) if conversation_id: span.set_attribute( SpanAttributes.MESSAGING_CONVERSATION_ID, conversation_id @@ -190,15 +189,19 @@ def _extract_queue_name_from_url(queue_url: str) -> str: return queue_url.split("/")[-1] def _create_processing_span( - self, queue_name: str, receipt_handle: str, message: Dict[str, Any] + self, + queue_name: str, + queue_url: str, + receipt_handle: str, + message: Dict[str, Any], ) -> None: message_attributes = message.get("MessageAttributes", {}) links = [] ctx = propagate.extract(message_attributes, getter=boto3sqs_getter) - if ctx: - for item in ctx.values(): - if hasattr(item, "get_span_context"): - links.append(Link(context=item.get_span_context())) + parent_span_ctx = trace.get_current_span(ctx).get_span_context() + if parent_span_ctx.is_valid: + links.append(Link(context=parent_span_ctx)) + span = self._tracer.start_span( name=f"{queue_name} process", links=links, kind=SpanKind.CONSUMER ) @@ -208,11 +211,12 @@ def _create_processing_span( Boto3SQSInstrumentor._enrich_span( span, queue_name, + queue_url, message_id=message_id, operation=MessagingOperationValues.PROCESS, ) - def _wrap_send_message(self) -> None: + def _wrap_send_message(self, sqs_class: type) -> None: def send_wrapper(wrapped, instance, args, kwargs): if context.get_value(_SUPPRESS_INSTRUMENTATION_KEY): return wrapped(*args, **kwargs) @@ -227,7 +231,7 @@ def send_wrapper(wrapped, instance, args, kwargs): kind=SpanKind.PRODUCER, end_on_exit=True, ) as span: - Boto3SQSInstrumentor._enrich_span(span, queue_name) + Boto3SQSInstrumentor._enrich_span(span, queue_name, queue_url) attributes = kwargs.pop("MessageAttributes", {}) propagate.inject(attributes, setter=boto3sqs_setter) retval = wrapped(*args, MessageAttributes=attributes, **kwargs) @@ -239,9 +243,9 @@ def send_wrapper(wrapped, instance, args, kwargs): ) return retval - wrap_function_wrapper(self._sqs_class, "send_message", send_wrapper) + wrap_function_wrapper(sqs_class, "send_message", send_wrapper) - def _wrap_send_message_batch(self) -> None: + def _wrap_send_message_batch(self, sqs_class: type) -> None: def send_batch_wrapper(wrapped, instance, args, kwargs): queue_url = kwargs.get("QueueUrl") entries = kwargs.get("Entries") @@ -260,12 +264,11 @@ def send_batch_wrapper(wrapped, instance, args, kwargs): for entry in entries: entry_id = entry["Id"] span = self._tracer.start_span( - name=f"{queue_name} send", - kind=SpanKind.PRODUCER, + name=f"{queue_name} send", kind=SpanKind.PRODUCER ) ids_to_spans[entry_id] = span Boto3SQSInstrumentor._enrich_span( - span, queue_name, conversation_id=entry_id + span, queue_name, queue_url, conversation_id=entry_id ) with trace.use_span(span): if "MessageAttributes" not in entry: @@ -288,15 +291,15 @@ def send_batch_wrapper(wrapped, instance, args, kwargs): return retval wrap_function_wrapper( - self._sqs_class, "send_message_batch", send_batch_wrapper + sqs_class, "send_message_batch", send_batch_wrapper ) - def _wrap_receive_message(self) -> None: + def _wrap_receive_message(self, sqs_class: type) -> None: def receive_message_wrapper(wrapped, instance, args, kwargs): queue_url = kwargs.get("QueueUrl") message_attribute_names = kwargs.pop("MessageAttributeNames", []) - message_attribute_names.append( - f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}*" + message_attribute_names.extend( + propagate.get_global_textmap().fields ) queue_name = Boto3SQSInstrumentor._extract_queue_name_from_url( queue_url @@ -309,6 +312,7 @@ def receive_message_wrapper(wrapped, instance, args, kwargs): Boto3SQSInstrumentor._enrich_span( span, queue_name, + queue_url, operation=MessagingOperationValues.RECEIVE, ) retval = wrapped( @@ -327,7 +331,7 @@ def receive_message_wrapper(wrapped, instance, args, kwargs): receipt_handle ) self._create_processing_span( - queue_name, receipt_handle, message + queue_name, queue_url, receipt_handle, message ) retval["Messages"] = Boto3SQSInstrumentor.ContextableList( messages @@ -335,10 +339,11 @@ def receive_message_wrapper(wrapped, instance, args, kwargs): return retval wrap_function_wrapper( - self._sqs_class, "receive_message", receive_message_wrapper + sqs_class, "receive_message", receive_message_wrapper ) - def _wrap_delete_message(self) -> None: + @staticmethod + def _wrap_delete_message(sqs_class: type) -> None: def delete_message_wrapper(wrapped, instance, args, kwargs): receipt_handle = kwargs.get("ReceiptHandle") if receipt_handle: @@ -346,10 +351,11 @@ def delete_message_wrapper(wrapped, instance, args, kwargs): return wrapped(*args, **kwargs) wrap_function_wrapper( - self._sqs_class, "delete_message", delete_message_wrapper + sqs_class, "delete_message", delete_message_wrapper ) - def _wrap_delete_message_batch(self) -> None: + @staticmethod + def _wrap_delete_message_batch(sqs_class: type) -> None: def delete_message_wrapper_batch(wrapped, instance, args, kwargs): entries = kwargs.get("Entries") for entry in entries: @@ -361,9 +367,7 @@ def delete_message_wrapper_batch(wrapped, instance, args, kwargs): return wrapped(*args, **kwargs) wrap_function_wrapper( - self._sqs_class, - "delete_message_batch", - delete_message_wrapper_batch, + sqs_class, "delete_message_batch", delete_message_wrapper_batch ) def _wrap_client_creation(self) -> None: @@ -375,43 +379,45 @@ def _wrap_client_creation(self) -> None: def client_wrapper(wrapped, instance, args, kwargs): retval = wrapped(*args, **kwargs) - if not self._did_decorate: - self._decorate_sqs() + self._decorate_sqs(type(retval)) return retval wrap_function_wrapper(boto3, "client", client_wrapper) - def _decorate_sqs(self) -> None: + def _decorate_sqs(self, sqs_class: type) -> None: """ Since botocore creates classes on the fly using schemas, we try to find the class that inherits from the base class and is SQS to wrap. """ # We define SQS client as the only client that implements send_message_batch - sqs_class = [ - cls - for cls in botocore.client.BaseClient.__subclasses__() - if hasattr(cls, "send_message_batch") - ] - if sqs_class: - self._sqs_class = sqs_class[0] - self._did_decorate = True - self._wrap_send_message() - self._wrap_send_message_batch() - self._wrap_receive_message() - self._wrap_delete_message() - self._wrap_delete_message_batch() - - def _un_decorate_sqs(self) -> None: - if self._did_decorate: - unwrap(self._sqs_class, "send_message") - unwrap(self._sqs_class, "send_message_batch") - unwrap(self._sqs_class, "receive_message") - unwrap(self._sqs_class, "delete_message") - unwrap(self._sqs_class, "delete_message_batch") - self._did_decorate = False + if not hasattr(sqs_class, "send_message_batch"): + return + + if getattr(sqs_class, _IS_SQS_INSTRUMENTED_ATTRIBUTE, False): + return + + setattr(sqs_class, _IS_SQS_INSTRUMENTED_ATTRIBUTE, True) + + self._wrap_send_message(sqs_class) + self._wrap_send_message_batch(sqs_class) + self._wrap_receive_message(sqs_class) + self._wrap_delete_message(sqs_class) + self._wrap_delete_message_batch(sqs_class) + + @staticmethod + def _un_decorate_sqs(sqs_class: type) -> None: + if not getattr(sqs_class, _IS_SQS_INSTRUMENTED_ATTRIBUTE, False): + return + + unwrap(sqs_class, "send_message") + unwrap(sqs_class, "send_message_batch") + unwrap(sqs_class, "receive_message") + unwrap(sqs_class, "delete_message") + unwrap(sqs_class, "delete_message_batch") + + setattr(sqs_class, _IS_SQS_INSTRUMENTED_ATTRIBUTE, False) def _instrument(self, **kwargs: Dict[str, Any]) -> None: - self._did_decorate: bool = False self._tracer_provider: Optional[TracerProvider] = kwargs.get( "tracer_provider" ) @@ -419,8 +425,12 @@ def _instrument(self, **kwargs: Dict[str, Any]) -> None: __name__, __version__, self._tracer_provider ) self._wrap_client_creation() - self._decorate_sqs() + + for client_cls in botocore.client.BaseClient.__subclasses__(): + self._decorate_sqs(client_cls) def _uninstrument(self, **kwargs: Dict[str, Any]) -> None: unwrap(boto3, "client") - self._un_decorate_sqs() + + for client_cls in botocore.client.BaseClient.__subclasses__(): + self._un_decorate_sqs(client_cls) diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/version.py index 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py index a42545a0d8..102e40693c 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py @@ -14,79 +14,72 @@ # pylint: disable=no-name-in-module -from unittest import TestCase +from contextlib import contextmanager +from typing import Any, Dict +from unittest import TestCase, mock import boto3 -import botocore.client +from botocore.awsrequest import AWSResponse from wrapt import BoundFunctionWrapper, FunctionWrapper from opentelemetry.instrumentation.boto3sqs import ( - _OPENTELEMETRY_ATTRIBUTE_IDENTIFIER, Boto3SQSGetter, Boto3SQSInstrumentor, Boto3SQSSetter, ) +from opentelemetry.semconv.trace import ( + MessagingDestinationKindValues, + MessagingOperationValues, + SpanAttributes, +) +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import SpanKind +from opentelemetry.trace.span import Span, format_span_id, format_trace_id -# pylint: disable=attribute-defined-outside-init -class TestBoto3SQSInstrumentor(TestCase): - def define_sqs_mock(self) -> None: - # pylint: disable=R0201 - class SQSClientMock(botocore.client.BaseClient): - def send_message(self, *args, **kwargs): - ... - - def send_message_batch(self, *args, **kwargs): - ... - - def receive_message(self, *args, **kwargs): - ... +def _make_sqs_client(): + return boto3.client( + "sqs", + region_name="us-east-1", + aws_access_key_id="dummy", + aws_secret_access_key="dummy", + ) - def delete_message(self, *args, **kwargs): - ... - def delete_message_batch(self, *args, **kwargs): - ... +class TestBoto3SQSInstrumentor(TestCase): + def _assert_instrumented(self, client): + self.assertIsInstance(boto3.client, FunctionWrapper) + self.assertIsInstance(client.send_message, BoundFunctionWrapper) + self.assertIsInstance(client.send_message_batch, BoundFunctionWrapper) + self.assertIsInstance(client.receive_message, BoundFunctionWrapper) + self.assertIsInstance(client.delete_message, BoundFunctionWrapper) + self.assertIsInstance( + client.delete_message_batch, BoundFunctionWrapper + ) - self._boto_sqs_mock = SQSClientMock + @staticmethod + @contextmanager + def _active_instrumentor(): + Boto3SQSInstrumentor().instrument() + try: + yield + finally: + Boto3SQSInstrumentor().uninstrument() def test_instrument_api_before_client_init(self) -> None: - instrumentation = Boto3SQSInstrumentor() - - instrumentation.instrument() - self.assertTrue(isinstance(boto3.client, FunctionWrapper)) - instrumentation.uninstrument() + with self._active_instrumentor(): + client = _make_sqs_client() + self._assert_instrumented(client) def test_instrument_api_after_client_init(self) -> None: - self.define_sqs_mock() - instrumentation = Boto3SQSInstrumentor() + client = _make_sqs_client() + with self._active_instrumentor(): + self._assert_instrumented(client) - instrumentation.instrument() - self.assertTrue(isinstance(boto3.client, FunctionWrapper)) - self.assertTrue( - isinstance(self._boto_sqs_mock.send_message, BoundFunctionWrapper) - ) - self.assertTrue( - isinstance( - self._boto_sqs_mock.send_message_batch, BoundFunctionWrapper - ) - ) - self.assertTrue( - isinstance( - self._boto_sqs_mock.receive_message, BoundFunctionWrapper - ) - ) - self.assertTrue( - isinstance( - self._boto_sqs_mock.delete_message, BoundFunctionWrapper - ) - ) - self.assertTrue( - isinstance( - self._boto_sqs_mock.delete_message_batch, BoundFunctionWrapper - ) - ) - instrumentation.uninstrument() + def test_instrument_multiple_clients(self): + with self._active_instrumentor(): + self._assert_instrumented(_make_sqs_client()) + self._assert_instrumented(_make_sqs_client()) class TestBoto3SQSGetter(TestCase): @@ -101,29 +94,17 @@ def test_get_none(self) -> None: def test_get_value(self) -> None: key = "test" value = "value" - carrier = { - f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key}": { - "StringValue": value, - "DataType": "String", - } - } + carrier = {key: {"StringValue": value, "DataType": "String"}} val = self.getter.get(carrier, key) self.assertEqual(val, [value]) def test_keys(self): - key1 = "test1" - value1 = "value1" - key2 = "test2" - value2 = "value2" carrier = { - f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key1}": { - "StringValue": value1, - "DataType": "String", - }, - key2: {"StringValue": value2, "DataType": "String"}, + "test1": {"StringValue": "value1", "DataType": "String"}, + "test2": {"StringValue": "value2", "DataType": "String"}, } keys = self.getter.keys(carrier) - self.assertEqual(keys, [key1, key2]) + self.assertEqual(keys, list(carrier.keys())) def test_keys_empty(self): keys = self.getter.keys({}) @@ -145,8 +126,188 @@ def test_simple(self): for dict_key, dict_val in carrier[original_key].items(): self.assertEqual(original_value[dict_key], dict_val) # Ensure the new key is added well - self.assertIn( - f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key}", carrier.keys() + self.assertEqual(carrier[key]["StringValue"], value) + + +class TestBoto3SQSInstrumentation(TestBase): + def setUp(self): + super().setUp() + self._reset_instrumentor() + Boto3SQSInstrumentor().instrument() + + self._client = _make_sqs_client() + self._queue_name = "MyQueue" + self._queue_url = f"https://sqs.us-east-1.amazonaws.com/123456789012/{self._queue_name}" + + def tearDown(self): + super().tearDown() + Boto3SQSInstrumentor().uninstrument() + self._reset_instrumentor() + + @staticmethod + def _reset_instrumentor(): + Boto3SQSInstrumentor.received_messages_spans.clear() + Boto3SQSInstrumentor.current_span_related_to_token = None + Boto3SQSInstrumentor.current_context_token = None + + @staticmethod + def _make_aws_response_func(response): + def _response_func(*args, **kwargs): + return AWSResponse("http://127.0.0.1", 200, {}, "{}"), response + + return _response_func + + @contextmanager + def _mocked_endpoint(self, response): + response_func = self._make_aws_response_func(response) + with mock.patch( + "botocore.endpoint.Endpoint.make_request", new=response_func + ): + yield + + def _assert_injected_span(self, msg_attrs: Dict[str, Any], span: Span): + trace_parent = msg_attrs["traceparent"]["StringValue"] + ctx = span.get_span_context() + self.assertEqual( + self._to_trace_parent(ctx.trace_id, ctx.span_id), + trace_parent.lower(), ) - new_value = carrier[f"{_OPENTELEMETRY_ATTRIBUTE_IDENTIFIER}{key}"] - self.assertEqual(new_value["StringValue"], value) + + def _default_span_attrs(self): + return { + SpanAttributes.MESSAGING_SYSTEM: "aws.sqs", + SpanAttributes.MESSAGING_DESTINATION: self._queue_name, + SpanAttributes.MESSAGING_DESTINATION_KIND: MessagingDestinationKindValues.QUEUE.value, + SpanAttributes.MESSAGING_URL: self._queue_url, + } + + @staticmethod + def _to_trace_parent(trace_id: int, span_id: int) -> str: + return f"00-{format_trace_id(trace_id)}-{format_span_id(span_id)}-01".lower() + + def _get_only_span(self): + spans = self.get_finished_spans() + self.assertEqual(1, len(spans)) + return spans[0] + + @staticmethod + def _make_message(message_id: str, body: str, receipt: str): + return { + "MessageId": message_id, + "ReceiptHandle": receipt, + "MD5OfBody": "777", + "Body": body, + "Attributes": {}, + "MD5OfMessageAttributes": "111", + "MessageAttributes": {}, + } + + def _add_trace_parent( + self, message: Dict[str, Any], trace_id: int, span_id: int + ): + message["MessageAttributes"]["traceparent"] = { + "StringValue": self._to_trace_parent(trace_id, span_id), + "DataType": "String", + } + + def test_send_message(self): + message_id = "123456789" + mock_response = { + "MD5OfMessageBody": "1234", + "MD5OfMessageAttributes": "5678", + "MD5OfMessageSystemAttributes": "9012", + "MessageId": message_id, + "SequenceNumber": "0", + } + + message_attrs = {} + + with self._mocked_endpoint(mock_response): + self._client.send_message( + QueueUrl=self._queue_url, + MessageBody="hello msg", + MessageAttributes=message_attrs, + ) + + span = self._get_only_span() + self.assertEqual(f"{self._queue_name} send", span.name) + self.assertEqual(SpanKind.PRODUCER, span.kind) + self.assertEqual( + { + SpanAttributes.MESSAGING_MESSAGE_ID: message_id, + **self._default_span_attrs(), + }, + span.attributes, + ) + self._assert_injected_span(message_attrs, span) + + def test_receive_message(self): + msg_def = { + "1": {"receipt": "01", "trace_id": 10, "span_id": 1}, + "2": {"receipt": "02", "trace_id": 20, "span_id": 2}, + } + + mock_response = {"Messages": []} + for msg_id, attrs in msg_def.items(): + message = self._make_message( + msg_id, f"hello {msg_id}", attrs["receipt"] + ) + self._add_trace_parent( + message, attrs["trace_id"], attrs["span_id"] + ) + mock_response["Messages"].append(message) + + message_attr_names = [] + + with self._mocked_endpoint(mock_response): + response = self._client.receive_message( + QueueUrl=self._queue_url, + MessageAttributeNames=message_attr_names, + ) + + self.assertIn("traceparent", message_attr_names) + + # receive span + span = self._get_only_span() + self.assertEqual(f"{self._queue_name} receive", span.name) + self.assertEqual(SpanKind.CONSUMER, span.kind) + self.assertEqual( + { + SpanAttributes.MESSAGING_OPERATION: MessagingOperationValues.RECEIVE.value, + **self._default_span_attrs(), + }, + span.attributes, + ) + + self.memory_exporter.clear() + + # processing spans + self.assertEqual(2, len(response["Messages"])) + for msg in response["Messages"]: + msg_id = msg["MessageId"] + attrs = msg_def[msg_id] + with self._mocked_endpoint(None): + self._client.delete_message( + QueueUrl=self._queue_url, ReceiptHandle=attrs["receipt"] + ) + + span = self._get_only_span() + self.assertEqual(f"{self._queue_name} process", span.name) + + # processing span attributes + self.assertEqual( + { + SpanAttributes.MESSAGING_MESSAGE_ID: msg_id, + SpanAttributes.MESSAGING_OPERATION: MessagingOperationValues.PROCESS.value, + **self._default_span_attrs(), + }, + span.attributes, + ) + + # processing span links + self.assertEqual(1, len(span.links)) + link = span.links[0] + self.assertEqual(attrs["trace_id"], link.context.trace_id) + self.assertEqual(attrs["span_id"], link.context.span_id) + + self.memory_exporter.clear() diff --git a/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg b/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg index 4f39bb1a4b..1b4d74ea8b 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = moto[all] ~= 2.2.6 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 markupsafe==2.0.1 [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py index 4e3130b5d1..b6a1c3aa57 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py @@ -35,7 +35,7 @@ class _AwsSdkCallContext: Args: service: the AWS service (e.g. s3, lambda, ...) which is called - service_id: the name of the service in propper casing + service_id: the name of the service in proper casing operation: the called operation (e.g. ListBuckets, Invoke, ...) of the AWS service. params: a dict of input parameters passed to the service operation. 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-celery/setup.cfg b/instrumentation/opentelemetry-instrumentation-celery/setup.cfg index c5c31c79e0..8205545ecd 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-celery/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = pytest - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE b/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/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-confluent-kafka/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-confluent-kafka/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/setup.cfg b/instrumentation/opentelemetry-instrumentation-confluent-kafka/setup.cfg index 302127afa6..94ffffcff7 100644 --- a/instrumentation/opentelemetry-instrumentation-confluent-kafka/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/setup.cfg @@ -28,20 +28,19 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 + opentelemetry-api ~= 1.12 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg b/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg index fd1aaf074a..bb4f713b72 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py index 2559466221..1afeb5499c 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py @@ -46,12 +46,12 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.dbapi.version import __version__ from opentelemetry.instrumentation.utils import ( - _generate_opentelemetry_traceparent, - _generate_sql_comment, + _add_sql_comment, + _get_opentelemetry_values, unwrap, ) from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import Span, SpanKind, TracerProvider, get_tracer +from opentelemetry.trace import SpanKind, TracerProvider, get_tracer _logger = logging.getLogger(__name__) @@ -105,6 +105,7 @@ def wrap_connect( capture_parameters: bool = False, enable_commenter: bool = False, db_api_integration_factory=None, + commenter_options: dict = None, ): """Integrate with DB API library. https://www.python.org/dev/peps/pep-0249/ @@ -119,6 +120,8 @@ def wrap_connect( tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to use. If omitted the current configured one is used. capture_parameters: Configure if db.statement.parameters should be captured. + enable_commenter: Flag to enable/disable sqlcommenter. + commenter_options: Configurations for tags to be appended at the sql query. """ db_api_integration_factory = ( @@ -140,6 +143,8 @@ def wrap_connect_( tracer_provider=tracer_provider, capture_parameters=capture_parameters, enable_commenter=enable_commenter, + commenter_options=commenter_options, + connect_module=connect_module, ) return db_integration.wrapped_connection(wrapped, args, kwargs) @@ -173,6 +178,7 @@ def instrument_connection( tracer_provider: typing.Optional[TracerProvider] = None, capture_parameters: bool = False, enable_commenter: bool = False, + commenter_options: dict = None, ): """Enable instrumentation in a database connection. @@ -185,6 +191,9 @@ def instrument_connection( tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to use. If omitted the current configured one is used. capture_parameters: Configure if db.statement.parameters should be captured. + enable_commenter: Flag to enable/disable sqlcommenter. + commenter_options: Configurations for tags to be appended at the sql query. + Returns: An instrumented connection. """ @@ -200,6 +209,7 @@ def instrument_connection( tracer_provider=tracer_provider, capture_parameters=capture_parameters, enable_commenter=enable_commenter, + commenter_options=commenter_options, ) db_integration.get_connection_attributes(connection) return get_traced_connection_proxy(connection, db_integration) @@ -231,6 +241,8 @@ def __init__( tracer_provider: typing.Optional[TracerProvider] = None, capture_parameters: bool = False, enable_commenter: bool = False, + commenter_options: dict = None, + connect_module: typing.Callable[..., typing.Any] = None, ): self.connection_attributes = connection_attributes if self.connection_attributes is None: @@ -249,11 +261,13 @@ def __init__( ) self.capture_parameters = capture_parameters self.enable_commenter = enable_commenter + self.commenter_options = commenter_options self.database_system = database_system self.connection_props = {} self.span_attributes = {} self.name = "" self.database = "" + self.connect_module = connect_module def wrapped_connection( self, @@ -335,12 +349,18 @@ class CursorTracer: def __init__(self, db_api_integration: DatabaseApiIntegration) -> None: self._db_api_integration = db_api_integration self._commenter_enabled = self._db_api_integration.enable_commenter + self._commenter_options = ( + self._db_api_integration.commenter_options + if self._db_api_integration.commenter_options + else {} + ) + self._connect_module = self._db_api_integration.connect_module def _populate_span( self, span: trace_api.Span, cursor, - *args: typing.Tuple[typing.Any, typing.Any] + *args: typing.Tuple[typing.Any, typing.Any], ): if not span.is_recording(): return @@ -375,21 +395,12 @@ def get_statement(self, cursor, args): # pylint: disable=no-self-use return statement.decode("utf8", "replace") return statement - @staticmethod - def _generate_comment(span: Span) -> str: - span_context = span.get_span_context() - meta = {} - if span_context.is_valid: - meta.update(_generate_opentelemetry_traceparent(span)) - # TODO(schekuri): revisit to enrich with info such as route, db_driver etc... - return _generate_sql_comment(**meta) - def traced_execution( self, cursor, query_method: typing.Callable[..., typing.Any], *args: typing.Tuple[typing.Any, typing.Any], - **kwargs: typing.Dict[typing.Any, typing.Any] + **kwargs: typing.Dict[typing.Any, typing.Any], ): name = self.get_operation_name(cursor, args) if not name: @@ -405,12 +416,33 @@ def traced_execution( self._populate_span(span, cursor, *args) if args and self._commenter_enabled: try: - comment = self._generate_comment(span) - if isinstance(args[0], bytes): - comment = comment.encode("utf8") args_list = list(args) - args_list[0] += comment + commenter_data = dict( + # Psycopg2/framework information + db_driver=f"psycopg2:{self._connect_module.__version__.split(' ')[0]}", + dbapi_threadsafety=self._connect_module.threadsafety, + dbapi_level=self._connect_module.apilevel, + libpq_version=self._connect_module.__libpq_version__, + driver_paramstyle=self._connect_module.paramstyle, + ) + if self._commenter_options.get( + "opentelemetry_values", True + ): + commenter_data.update(**_get_opentelemetry_values()) + + # Filter down to just the requested attributes. + commenter_data = { + k: v + for k, v in commenter_data.items() + if self._commenter_options.get(k, True) + } + statement = _add_sql_comment( + args_list[0], **commenter_data + ) + + args_list[0] = statement args = tuple(args_list) + except Exception as exc: # pylint: disable=broad-except _logger.exception( "Exception while generating sql comment: %s", exc 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 d0074fee82..d67f786816 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.32b0" +__version__ = "0.33b0" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py b/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py index 2644cb2fcd..af2cbeea15 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py @@ -229,19 +229,30 @@ def test_executemany(self): ) def test_executemany_comment(self): + + connect_module = mock.MagicMock() + connect_module.__version__ = mock.MagicMock() + connect_module.__libpq_version__ = 123 + connect_module.apilevel = 123 + connect_module.threadsafety = 123 + connect_module.paramstyle = "test" + db_integration = dbapi.DatabaseApiIntegration( - "testname", "testcomponent", enable_commenter=True + "testname", + "testcomponent", + enable_commenter=True, + commenter_options={"db_driver": False, "dbapi_level": False}, + connect_module=connect_module, ) mock_connection = db_integration.wrapped_connection( mock_connect, {}, {} ) cursor = mock_connection.cursor() - cursor.executemany("Test query") - spans_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans_list), 1) - span = spans_list[0] - comment = dbapi.CursorTracer._generate_comment(span) - self.assertIn(comment, cursor.query) + cursor.executemany("Select 1;") + self.assertRegex( + cursor.query, + r"Select 1 /\*dbapi_threadsafety=123,driver_paramstyle='test',libpq_version=123,traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", + ) def test_callproc(self): db_integration = dbapi.DatabaseApiIntegration( diff --git a/instrumentation/opentelemetry-instrumentation-django/setup.cfg b/instrumentation/opentelemetry-instrumentation-django/setup.cfg index 5b3c5a7a93..cb60870ffe 100644 --- a/instrumentation/opentelemetry-instrumentation-django/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-django/setup.cfg @@ -28,29 +28,28 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-util-http == 0.32b0 - opentelemetry-instrumentation-wsgi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-util-http == 0.33b0 + opentelemetry-instrumentation-wsgi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 [options.extras_require] asgi = - opentelemetry-instrumentation-asgi == 0.32b0 + opentelemetry-instrumentation-asgi == 0.33b0 test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 4b8dec4e64..680ff4e8f7 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py @@ -205,6 +205,7 @@ def response_hook(span, request, response): from opentelemetry.instrumentation.django.package import _instruments from opentelemetry.instrumentation.django.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.metrics import get_meter from opentelemetry.trace import get_tracer DJANGO_2_0 = django_version >= (2, 0) @@ -244,19 +245,29 @@ def _instrument(self, **kwargs): return tracer_provider = kwargs.get("tracer_provider") + meter_provider = kwargs.get("meter_provider") tracer = get_tracer( __name__, __version__, tracer_provider=tracer_provider, ) - + meter = get_meter(__name__, __version__, meter_provider=meter_provider) _DjangoMiddleware._tracer = tracer - + _DjangoMiddleware._meter = meter _DjangoMiddleware._otel_request_hook = kwargs.pop("request_hook", None) _DjangoMiddleware._otel_response_hook = kwargs.pop( "response_hook", None ) - + _DjangoMiddleware._duration_histogram = meter.create_histogram( + name="http.server.duration", + unit="ms", + description="measures the duration of the inbound http request", + ) + _DjangoMiddleware._active_request_counter = meter.create_up_down_counter( + name="http.server.active_requests", + unit="requests", + description="measures the number of concurrent HTTP requests those are currently in flight", + ) # This can not be solved, but is an inherent problem of this approach: # the order of middleware entries matters, and here you have no control # on that: diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py index 660be75cf7..42cdf40812 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py @@ -15,6 +15,7 @@ import types from logging import getLogger from time import time +from timeit import default_timer from typing import Callable from django import VERSION as django_version @@ -41,7 +42,12 @@ from opentelemetry.instrumentation.wsgi import wsgi_getter from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import Span, SpanKind, use_span -from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs +from opentelemetry.util.http import ( + _parse_active_request_count_attrs, + _parse_duration_attrs, + get_excluded_urls, + get_traced_request_attrs, +) try: from django.core.urlresolvers import ( # pylint: disable=no-name-in-module @@ -139,10 +145,19 @@ class _DjangoMiddleware(MiddlewareMixin): _environ_token = "opentelemetry-instrumentor-django.token" _environ_span_key = "opentelemetry-instrumentor-django.span_key" _environ_exception_key = "opentelemetry-instrumentor-django.exception_key" - + _environ_active_request_attr_key = ( + "opentelemetry-instrumentor-django.active_request_attr_key" + ) + _environ_duration_attr_key = ( + "opentelemetry-instrumentor-django.duration_attr_key" + ) + _environ_timer_key = "opentelemetry-instrumentor-django.timer_key" _traced_request_attrs = get_traced_request_attrs("DJANGO") _excluded_urls = get_excluded_urls("DJANGO") _tracer = None + _meter = None + _duration_histogram = None + _active_request_counter = None _otel_request_hook: Callable[[Span, HttpRequest], None] = None _otel_response_hook: Callable[ @@ -171,6 +186,7 @@ def _get_span_name(request): except Resolver404: return f"HTTP {request.method}" + # pylint: disable=too-many-locals def process_request(self, request): # request.META is a dictionary containing all available HTTP headers # Read more about request.META here: @@ -185,7 +201,6 @@ def process_request(self, request): # pylint:disable=W0212 request._otel_start_time = time() - request_meta = request.META if is_asgi_request: @@ -208,7 +223,16 @@ def process_request(self, request): ) attributes = collect_request_attributes(carrier) + active_requests_count_attrs = _parse_active_request_count_attrs( + attributes + ) + duration_attrs = _parse_duration_attrs(attributes) + request.META[ + self._environ_active_request_attr_key + ] = active_requests_count_attrs + request.META[self._environ_duration_attr_key] = duration_attrs + self._active_request_counter.add(1, active_requests_count_attrs) if span.is_recording(): attributes = extract_attributes_from_object( request, self._traced_request_attrs, attributes @@ -242,7 +266,8 @@ def process_request(self, request): activation = use_span(span, end_on_exit=True) activation.__enter__() # pylint: disable=E1101 - + request_start_time = default_timer() + request.META[self._environ_timer_key] = request_start_time request.META[self._environ_activation_key] = activation request.META[self._environ_span_key] = span if token: @@ -281,6 +306,7 @@ def process_exception(self, request, exception): request.META[self._environ_exception_key] = exception # pylint: disable=too-many-branches + # pylint: disable=too-many-locals def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response @@ -291,6 +317,17 @@ def process_response(self, request, response): activation = request.META.pop(self._environ_activation_key, None) span = request.META.pop(self._environ_span_key, None) + active_requests_count_attrs = request.META.pop( + self._environ_active_request_attr_key, None + ) + duration_attrs = request.META.pop( + self._environ_duration_attr_key, None + ) + if duration_attrs: + duration_attrs[ + SpanAttributes.HTTP_STATUS_CODE + ] = response.status_code + request_start_time = request.META.pop(self._environ_timer_key, None) if activation and span: if is_asgi_request: @@ -341,6 +378,12 @@ def process_response(self, request, response): else: activation.__exit__(None, None, None) + if request_start_time is not None: + duration = max( + round((default_timer() - request_start_time) * 1000), 0 + ) + self._duration_histogram.record(duration, duration_attrs) + self._active_request_counter.add(-1, active_requests_count_attrs) if request.META.get(self._environ_token, None) is not None: detach(request.META.get(self._environ_token)) request.META.pop(self._environ_token) diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py index 5fe51fca52..89c1b93008 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py @@ -23,7 +23,7 @@ from django.db.backends.utils import CursorDebugWrapper from opentelemetry.instrumentation.utils import ( - _generate_sql_comment, + _add_sql_comment, _get_opentelemetry_values, ) from opentelemetry.trace.propagation.tracecontext import ( @@ -84,7 +84,8 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T: db_driver = context["connection"].settings_dict.get("ENGINE", "") resolver_match = self.request.resolver_match - sql_comment = _generate_sql_comment( + sql = _add_sql_comment( + sql, # Information about the controller. controller=resolver_match.view_name if resolver_match and with_controller @@ -112,7 +113,6 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T: # See: # * https://github.com/basecamp/marginalia/issues/61 # * https://github.com/basecamp/marginalia/pull/80 - sql += sql_comment # Add the query to the query log if debugging. if isinstance(context["cursor"], CursorDebugWrapper): diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/package.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/package.py index 5b3ba08106..290061a36f 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/package.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/package.py @@ -14,3 +14,4 @@ _instruments = ("django >= 1.10",) +_supports_metrics = True 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 05457de43d..8b584bfc3b 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -15,6 +15,7 @@ # pylint: disable=E0611 from sys import modules +from timeit import default_timer from unittest.mock import Mock, patch from django import VERSION, conf @@ -32,6 +33,10 @@ set_global_response_propagator, ) from opentelemetry.sdk import resources +from opentelemetry.sdk.metrics.export import ( + HistogramDataPoint, + NumberDataPoint, +) from opentelemetry.sdk.trace import Span from opentelemetry.sdk.trace.id_generator import RandomIdGenerator from opentelemetry.semconv.trace import SpanAttributes @@ -45,6 +50,8 @@ from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, + _active_requests_count_attrs, + _duration_attrs, get_excluded_urls, get_traced_request_attrs, ) @@ -406,6 +413,64 @@ def test_trace_response_headers(self): ) self.memory_exporter.clear() + # pylint: disable=too-many-locals + def test_wsgi_metrics(self): + _expected_metric_names = [ + "http.server.active_requests", + "http.server.duration", + ] + _recommended_attrs = { + "http.server.active_requests": _active_requests_count_attrs, + "http.server.duration": _duration_attrs, + } + start = default_timer() + for _ in range(3): + response = Client().get("/span_name/1234/") + self.assertEqual(response.status_code, 200) + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histrogram_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) + 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) + histrogram_data_point_seen = True + self.assertAlmostEqual( + duration, point.sum, delta=100 + ) + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + self.assertEqual(point.value, 0) + for attr in point.attributes: + self.assertIn( + attr, _recommended_attrs[metric.name] + ) + self.assertTrue(histrogram_data_point_seen and number_data_point_seen) + + def test_wsgi_metrics_unistrument(self): + Client().get("/span_name/1234/") + _django_instrumentor.uninstrument() + Client().get("/span_name/1234/") + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertEqual(1, point.count) + if isinstance(point, NumberDataPoint): + self.assertEqual(0, point.value) + class TestMiddlewareWithTracerProvider(WsgiTestBase): @classmethod diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_sqlcommenter.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_sqlcommenter.py index b162cc1f2a..f9b8ed5233 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_sqlcommenter.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_sqlcommenter.py @@ -88,7 +88,7 @@ def test_query_wrapper(self, trace_capture): execute_mock_obj = MagicMock() qw_instance( execute_mock_obj, - "Select 1", + "Select 1;", MagicMock("test"), MagicMock("test1"), MagicMock(), @@ -97,7 +97,7 @@ def test_query_wrapper(self, trace_capture): self.assertEqual( output_sql, "Select 1 /*app_name='app',controller='view',route='route',traceparent='%%2Atraceparent%%3D%%2700-0000000" - "00000000000000000deadbeef-000000000000beef-00'*/", + "00000000000000000deadbeef-000000000000beef-00'*/;", ) @patch( diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg b/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg index 4cd1963136..72d0c48b27 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 elasticsearch-dsl >= 2.0 [options.packages.find] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg b/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg index 8759a58a46..d21231010c 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg @@ -28,28 +28,27 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-instrumentation-wsgi == 0.32b0 - opentelemetry-util-http == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-instrumentation-wsgi == 0.33b0 + opentelemetry-util-http == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 packaging >= 20.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 parameterized == 0.7.4 [options.packages.find] 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 cdf2c3553f..b123203c77 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -143,6 +143,7 @@ def response_hook(span, req, resp): from logging import getLogger from sys import exc_info +from time import time_ns from typing import Collection import falcon @@ -164,7 +165,6 @@ def response_hook(span, req, resp): ) from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status -from opentelemetry.util._time import _time_ns from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs _logger = getLogger(__name__) @@ -253,7 +253,7 @@ def __call__(self, env, start_response): if self._otel_excluded_urls.url_disabled(env.get("PATH_INFO", "/")): return super().__call__(env, start_response) - start_time = _time_ns() + start_time = time_ns() span, token = _start_internal_or_server_span( tracer=self._otel_tracer, 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE b/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-fastapi/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-fastapi/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-fastapi/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-fastapi/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg b/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg index 35ba30254c..f17dd9e3f6 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg @@ -28,23 +28,22 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-instrumentation-asgi == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-instrumentation-asgi == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.entry_points] opentelemetry_instrumentor = @@ -52,7 +51,7 @@ opentelemetry_instrumentor = [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 requests ~= 2.23.0 # needed for testclient [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py index 5cf17d36f0..1c76c8bb50 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py @@ -54,8 +54,8 @@ async def foobar(): Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. The server request hook takes in a server span and ASGI -scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method recieve is called. +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. The server request hook takes in a server span and ASGI +scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method receive is called. The client response hook is called with the internal span and an ASGI event which is sent as a dictionary for when the method send is called. .. code-block:: python 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py index e4a0960a26..0d42e7533c 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py @@ -490,7 +490,7 @@ def test_http_custom_response_headers_in_span_attributes(self): def test_http_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.reponse.header.custom_test_header_3": ( + "http.response.header.custom_test_header_3": ( "test-header-value-3", ), } @@ -633,7 +633,7 @@ def test_web_socket_custom_response_headers_in_span_attributes(self): def test_web_socket_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.reponse.header.custom_test_header_3": ( + "http.response.header.custom_test_header_3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-flask/README.rst b/instrumentation/opentelemetry-instrumentation-flask/README.rst index d3092cc4a7..a708e7937a 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/README.rst +++ b/instrumentation/opentelemetry-instrumentation-flask/README.rst @@ -41,7 +41,7 @@ You can also pass the comma delimited regexes to the ``instrument_app`` method d Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment (flask.request.environ). +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment (flask.request.environ). Response_headers is a list of key-value (tuples) representing the response headers returned from the response. .. code-block:: python @@ -61,6 +61,6 @@ Flask Request object reference: https://flask.palletsprojects.com/en/2.0.x/api/# References ---------- -* `OpenTelemetry Flask Instrumentation `_ +* `OpenTelemetry Flask Instrumentation `_ * `OpenTelemetry Project `_ * `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-flask/setup.cfg b/instrumentation/opentelemetry-instrumentation-flask/setup.cfg index f8d48c1dd6..fef2fce338 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-flask/setup.cfg @@ -28,27 +28,26 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-util-http == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-instrumentation-wsgi == 0.32b0 - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-util-http == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-instrumentation-wsgi == 0.33b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 markupsafe==2.0.1 [options.entry_points] 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 cca8743556..dcddbc40bf 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -68,7 +68,7 @@ def hello(): Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment (flask.request.environ). +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment (flask.request.environ). Response_headers is a list of key-value (tuples) representing the response headers returned from the response. .. code-block:: python @@ -141,6 +141,8 @@ def response_hook(span: Span, status: str, response_headers: List): """ from logging import getLogger +from time import time_ns +from timeit import default_timer from typing import Collection import flask @@ -154,8 +156,8 @@ def response_hook(span: Span, status: str, response_headers: List): get_global_response_propagator, ) from opentelemetry.instrumentation.utils import _start_internal_or_server_span +from opentelemetry.metrics import get_meter from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.util._time import _time_ns from opentelemetry.util.http import get_excluded_urls, parse_excluded_urls _logger = getLogger(__name__) @@ -165,7 +167,6 @@ def response_hook(span: Span, status: str, response_headers: List): _ENVIRON_ACTIVATION_KEY = "opentelemetry-flask.activation_key" _ENVIRON_TOKEN = "opentelemetry-flask.token" - _excluded_urls_from_env = get_excluded_urls("FLASK") @@ -178,13 +179,26 @@ def get_default_span_name(): return span_name -def _rewrapped_app(wsgi_app, response_hook=None, excluded_urls=None): +def _rewrapped_app( + wsgi_app, + active_requests_counter, + duration_histogram, + response_hook=None, + excluded_urls=None, +): def _wrapped_app(wrapped_app_environ, start_response): # We want to measure the time for route matching, etc. # In theory, we could start the span here and use # update_name later but that API is "highly discouraged" so # we better avoid it. - wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = _time_ns() + wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = time_ns() + start = default_timer() + attributes = otel_wsgi.collect_request_attributes(wrapped_app_environ) + active_requests_count_attrs = ( + otel_wsgi._parse_active_request_count_attrs(attributes) + ) + duration_attrs = otel_wsgi._parse_duration_attrs(attributes) + active_requests_counter.add(1, active_requests_count_attrs) def _start_response(status, response_headers, *args, **kwargs): if flask.request and ( @@ -204,6 +218,11 @@ def _start_response(status, response_headers, *args, **kwargs): otel_wsgi.add_response_attributes( span, status, response_headers ) + status_code = otel_wsgi._parse_status_code(status) + if status_code is not None: + duration_attrs[ + SpanAttributes.HTTP_STATUS_CODE + ] = status_code if ( span.is_recording() and span.kind == trace.SpanKind.SERVER @@ -223,13 +242,19 @@ def _start_response(status, response_headers, *args, **kwargs): response_hook(span, status, response_headers) return start_response(status, response_headers, *args, **kwargs) - return wsgi_app(wrapped_app_environ, _start_response) + result = wsgi_app(wrapped_app_environ, _start_response) + duration = max(round((default_timer() - start) * 1000), 0) + duration_histogram.record(duration, duration_attrs) + active_requests_counter.add(-1, active_requests_count_attrs) + return result return _wrapped_app def _wrapped_before_request( - request_hook=None, tracer=None, excluded_urls=None + request_hook=None, + tracer=None, + excluded_urls=None, ): def _before_request(): if excluded_urls and excluded_urls.url_disabled(flask.request.url): @@ -278,7 +303,9 @@ def _before_request(): return _before_request -def _wrapped_teardown_request(excluded_urls=None): +def _wrapped_teardown_request( + excluded_urls=None, +): def _teardown_request(exc): # pylint: disable=E1101 if excluded_urls and excluded_urls.url_disabled(flask.request.url): @@ -290,7 +317,6 @@ def _teardown_request(exc): # a way that doesn't run `before_request`, like when it is created # with `app.test_request_context`. return - if exc is None: activation.__exit__(None, None, None) else: @@ -310,6 +336,7 @@ class _InstrumentedFlask(flask.Flask): _tracer_provider = None _request_hook = None _response_hook = None + _meter_provider = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -317,8 +344,24 @@ def __init__(self, *args, **kwargs): self._original_wsgi_app = self.wsgi_app self._is_instrumented_by_opentelemetry = True + meter = get_meter( + __name__, __version__, _InstrumentedFlask._meter_provider + ) + duration_histogram = meter.create_histogram( + name="http.server.duration", + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + active_requests_counter = meter.create_up_down_counter( + name="http.server.active_requests", + unit="requests", + description="measures the number of concurrent HTTP requests that are currently in-flight", + ) + self.wsgi_app = _rewrapped_app( self.wsgi_app, + active_requests_counter, + duration_histogram, _InstrumentedFlask._response_hook, excluded_urls=_InstrumentedFlask._excluded_urls, ) @@ -367,6 +410,8 @@ def _instrument(self, **kwargs): if excluded_urls is None else parse_excluded_urls(excluded_urls) ) + meter_provider = kwargs.get("meter_provider") + _InstrumentedFlask._meter_provider = meter_provider flask.Flask = _InstrumentedFlask def _uninstrument(self, **kwargs): @@ -379,6 +424,7 @@ def instrument_app( response_hook=None, tracer_provider=None, excluded_urls=None, + meter_provider=None, ): if not hasattr(app, "_is_instrumented_by_opentelemetry"): app._is_instrumented_by_opentelemetry = False @@ -389,9 +435,25 @@ def instrument_app( if excluded_urls is not None else _excluded_urls_from_env ) + meter = get_meter(__name__, __version__, meter_provider) + duration_histogram = meter.create_histogram( + name="http.server.duration", + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + active_requests_counter = meter.create_up_down_counter( + name="http.server.active_requests", + unit="requests", + description="measures the number of concurrent HTTP requests that are currently in-flight", + ) + app._original_wsgi_app = app.wsgi_app app.wsgi_app = _rewrapped_app( - app.wsgi_app, response_hook, excluded_urls=excluded_urls + app.wsgi_app, + active_requests_counter, + duration_histogram, + response_hook, + excluded_urls=excluded_urls, ) tracer = trace.get_tracer(__name__, __version__, tracer_provider) diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py index b081564202..33bfe4ccba 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py @@ -14,3 +14,5 @@ _instruments = ("flask >= 1.0, < 3.0",) + +_supports_metrics = True 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index 2bcb097c7b..a64ca48d55 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from timeit import default_timer from unittest.mock import Mock, patch from flask import Flask, request @@ -23,7 +24,15 @@ get_global_response_propagator, set_global_response_propagator, ) -from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware +from opentelemetry.instrumentation.wsgi import ( + OpenTelemetryMiddleware, + _active_requests_count_attrs, + _duration_attrs, +) +from opentelemetry.sdk.metrics.export import ( + HistogramDataPoint, + NumberDataPoint, +) from opentelemetry.sdk.resources import Resource from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -49,6 +58,16 @@ def expected_attributes(override_attributes): return default_attributes +_expected_metric_names = [ + "http.server.active_requests", + "http.server.duration", +] +_recommended_attrs = { + "http.server.active_requests": _active_requests_count_attrs, + "http.server.duration": _duration_attrs, +} + + class TestProgrammatic(InstrumentationTest, WsgiTestBase): def setUp(self): super().setUp() @@ -250,6 +269,106 @@ def test_exclude_lists_from_explicit(self): span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) + def test_flask_metrics(self): + start = default_timer() + self.client.get("/hello/123") + self.client.get("/hello/321") + self.client.get("/hello/756") + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, _recommended_attrs[metric.name] + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_flask_metric_values(self): + start = default_timer() + self.client.post("/hello/756") + self.client.post("/hello/756") + self.client.post("/hello/756") + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + if isinstance(point, NumberDataPoint): + self.assertEqual(point.value, 0) + + def test_basic_metric_success(self): + self.client.get("/hello/756") + expected_duration_attributes = { + "http.method": "GET", + "http.host": "localhost", + "http.scheme": "http", + "http.flavor": "1.1", + "http.server_name": "localhost", + "net.host.port": 80, + "http.status_code": 200, + } + expected_requests_count_attributes = { + "http.method": "GET", + "http.host": "localhost", + "http.scheme": "http", + "http.flavor": "1.1", + "http.server_name": "localhost", + } + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metrics in resource_metric.scope_metrics: + for metric in scope_metrics.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertDictEqual( + expected_duration_attributes, + dict(point.attributes), + ) + self.assertEqual(point.count, 1) + elif isinstance(point, NumberDataPoint): + self.assertDictEqual( + expected_requests_count_attributes, + dict(point.attributes), + ) + self.assertEqual(point.value, 0) + + def test_metric_uninstrument(self): + self.client.delete("/hello/756") + FlaskInstrumentor().uninstrument_app(self.app) + self.client.delete("/hello/756") + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + class TestProgrammaticHooks(InstrumentationTest, WsgiTestBase): def setUp(self): diff --git a/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg b/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg index b6daab3a47..4d20e572bd 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg @@ -28,28 +28,27 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-sdk ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-sdk ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 - opentelemetry-sdk ~= 1.3 + opentelemetry-test-utils == 0.33b0 + opentelemetry-sdk ~= 1.12 protobuf ~= 3.13 [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py index f6de2a2d76..177bfe67b5 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py @@ -43,7 +43,8 @@ SimpleSpanProcessor(ConsoleSpanExporter()) ) - instrumentor = GrpcInstrumentorClient().instrument() + grpc_client_instrumentor = GrpcInstrumentorClient() + grpc_client_instrumentor.instrument() def run(): with grpc.insecure_channel("localhost:50051") as channel: @@ -180,7 +181,7 @@ class GrpcInstrumentorClient(BaseInstrumentor): Usage:: grpc_client_instrumentor = GrpcInstrumentorClient() - grpc.client_instrumentor.instrument() + grpc_client_instrumentor.instrument() """ 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-httpx/setup.cfg b/instrumentation/opentelemetry-instrumentation-httpx/setup.cfg index 66c7a23a7d..e60855da16 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-httpx/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-semantic-conventions == 0.33b0 [options.extras_require] test = - opentelemetry-sdk ~= 1.3 - opentelemetry-test-utils == 0.32b0 + opentelemetry-sdk ~= 1.12 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg b/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg index 94ca73214e..730e0ea253 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg @@ -28,7 +28,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -39,13 +38,13 @@ package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 markupsafe==2.0.1 [options.packages.find] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/setup.cfg b/instrumentation/opentelemetry-instrumentation-kafka-python/setup.cfg index 0e80c66a82..cb01ce573e 100644 --- a/instrumentation/opentelemetry-instrumentation-kafka-python/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = opentelemetry-api ~= 1.5 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-semantic-conventions == 0.32b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-semantic-conventions == 0.33b0 [options.extras_require] test = wrapt >= 1.0.0, < 2.0.0 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.entry_points] opentelemetry_instrumentor = 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-logging/setup.cfg b/instrumentation/opentelemetry-instrumentation-logging/setup.cfg index 9d423eff5e..cf5898df25 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-logging/setup.cfg @@ -28,7 +28,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -39,12 +38,12 @@ package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 d0074fee82..d67f786816 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.32b0" +__version__ = "0.33b0" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg b/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg index 6807e48896..316849980c 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation-dbapi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation-dbapi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-pika/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pika/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-pika/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-pika/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pika/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-pika/setup.cfg b/instrumentation/opentelemetry-instrumentation-pika/setup.cfg index 98ddc6f173..b5f7864ab9 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pika/setup.cfg @@ -28,14 +28,13 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: @@ -49,7 +48,7 @@ install_requires = test = pytest wrapt >= 1.0.0, < 2.0.0 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg b/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg index c26abdbe86..9b0d9ef3fd 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation-dbapi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation-dbapi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py index 4b7ff23ea6..ebad55cf2a 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py @@ -18,6 +18,68 @@ .. _Psycopg: http://initd.org/psycopg/ +SQLCOMMENTER +***************************************** +You can optionally configure Psycopg2 instrumentation to enable sqlcommenter which enriches +the query with contextual information. + +Usage +----- + +.. code:: python + + from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor + + Psycopg2Instrumentor().instrument(enable_commenter=True, commenter_options={}) + + +For example, +:: + + Invoking cursor.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter is enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" + + +SQLCommenter Configurations +*************************** +We can configure the tags to be appended to the sqlquery log by adding configuration inside commenter_options(default:{}) keyword + +db_driver = True(Default) or False + +For example, +:: +Enabling this flag will add psycopg2 and it's version which is /*psycopg2%%3A2.9.3*/ + +dbapi_threadsafety = True(Default) or False + +For example, +:: +Enabling this flag will add threadsafety /*dbapi_threadsafety=2*/ + +dbapi_level = True(Default) or False + +For example, +:: +Enabling this flag will add dbapi_level /*dbapi_level='2.0'*/ + +libpq_version = True(Default) or False + +For example, +:: +Enabling this flag will add libpq_version /*libpq_version=140001*/ + +driver_paramstyle = True(Default) or False + +For example, +:: +Enabling this flag will add driver_paramstyle /*driver_paramstyle='pyformat'*/ + +opentelemetry_values = True(Default) or False + +For example, +:: +Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ + Usage ----- @@ -77,6 +139,7 @@ def _instrument(self, **kwargs): """ tracer_provider = kwargs.get("tracer_provider") enable_sqlcommenter = kwargs.get("enable_commenter", False) + commenter_options = kwargs.get("commenter_options", {}) dbapi.wrap_connect( __name__, psycopg2, @@ -87,6 +150,7 @@ def _instrument(self, **kwargs): tracer_provider=tracer_provider, db_api_integration_factory=DatabaseApiIntegration, enable_commenter=enable_sqlcommenter, + commenter_options=commenter_options, ) def _uninstrument(self, **kwargs): 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_integration.py b/instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_integration.py index e974da7d60..f516a07882 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_integration.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_integration.py @@ -68,6 +68,7 @@ def get_dsn_parameters(self): # pylint: disable=no-self-use class TestPostgresqlIntegration(TestBase): def setUp(self): + super().setUp() self.cursor_mock = mock.patch( "opentelemetry.instrumentation.psycopg2.pg_cursor", MockCursor ) diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg index b2c14aa1a9..aeef01e67d 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/utils.py b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/utils.py index 361fb6e68c..029a7d07a7 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/utils.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/utils.py @@ -56,9 +56,9 @@ def __init__(self, connect_failure=None): self.sockets = [] def socket(self): # noqa: A002 - soket = MockSocket([], connect_failure=self.connect_failure) - self.sockets.append(soket) - return soket + mock_socket = MockSocket([], connect_failure=self.connect_failure) + self.sockets.append(mock_socket) + return mock_socket def __getattr__(self, name): return getattr(socket, name) diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg index 8fcedf2742..269ea49e37 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py index 171979dbfe..ba3afae11f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py @@ -223,7 +223,6 @@ def _instrument(self, **kwargs): request_hook = kwargs.get("request_hook", dummy_callback) response_hook = kwargs.get("response_hook", dummy_callback) failed_hook = kwargs.get("failed_hook", dummy_callback) - # Create and register a CommandTracer only the first time if self._commandtracer_instance is None: tracer = get_tracer(__name__, __version__, tracer_provider) @@ -235,7 +234,6 @@ def _instrument(self, **kwargs): failed_hook=failed_hook, ) monitoring.register(self._commandtracer_instance) - # If already created, just enable it self._commandtracer_instance.is_enabled = True 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE b/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymysql/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-pymysql/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-pymysql/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-pymysql/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg index 3c31d32b62..dd9253cccf 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation-dbapi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation-dbapi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg b/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg index d380dc5b7d..316253198d 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg @@ -28,29 +28,28 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-instrumentation == 0.32b0 - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation-wsgi == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation-wsgi == 0.33b0 + opentelemetry-util-http == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = werkzeug == 0.16.1 - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py index c225f2f11d..71db8a7426 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py @@ -55,7 +55,7 @@ --------------------------------- If you use Method 2 and then set tweens for your application with the ``pyramid.tweens`` setting, -you need to add ``opentelemetry.instrumentation.pyramid.trace_tween_factory`` explicity to the list, +you need to add ``opentelemetry.instrumentation.pyramid.trace_tween_factory`` explicitly to the list, *as well as* instrumenting the config as shown above. For example: 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 0f36b17e56..c9ebf7081e 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -13,6 +13,7 @@ # limitations under the License. from logging import getLogger +from time import time_ns from pyramid.events import BeforeTraversal from pyramid.httpexceptions import HTTPException, HTTPServerError @@ -27,7 +28,6 @@ from opentelemetry.instrumentation.pyramid.version import __version__ from opentelemetry.instrumentation.utils import _start_internal_or_server_span from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.util._time import _time_ns from opentelemetry.util.http import get_excluded_urls TWEEN_NAME = "opentelemetry.instrumentation.pyramid.trace_tween_factory" @@ -144,7 +144,7 @@ def trace_tween(request): return handler(request) request.environ[_ENVIRON_ENABLED_KEY] = True - request.environ[_ENVIRON_STARTTIME_KEY] = _time_ns() + request.environ[_ENVIRON_STARTTIME_KEY] = time_ns() response = None status = None 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-redis/LICENSE b/instrumentation/opentelemetry-instrumentation-redis/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-redis/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-redis/setup.cfg b/instrumentation/opentelemetry-instrumentation-redis/setup.cfg index e0bd1858f4..d6afa117bb 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-redis/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 wrapt >= 1.12.1 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 opentelemetry-sdk ~= 1.3 [options.packages.find] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py b/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py index 3780f0c245..3d5479e731 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py +++ b/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py @@ -21,9 +21,16 @@ class TestRedis(TestBase): + def setUp(self): + super().setUp() + RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) + + def tearDown(self): + super().tearDown() + RedisInstrumentor().uninstrument() + def test_span_properties(self): redis_client = redis.Redis() - RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) with mock.patch.object(redis_client, "connection"): redis_client.get("key") @@ -36,7 +43,6 @@ def test_span_properties(self): def test_not_recording(self): redis_client = redis.Redis() - RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) mock_tracer = mock.Mock() mock_span = mock.Mock() @@ -53,7 +59,6 @@ def test_not_recording(self): def test_instrument_uninstrument(self): redis_client = redis.Redis() - RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) with mock.patch.object(redis_client, "connection"): redis_client.get("key") diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE b/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/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-remoulade/setup.cfg b/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg index a70dd83781..b746df5a5d 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg @@ -40,12 +40,12 @@ package_dir= packages=find_namespace: install_requires = opentelemetry-api ~= 1.10 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 opentelemetry-sdk ~= 1.10 [options.packages.find] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py index 4704111bdd..ff25b3f6de 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py +++ b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py @@ -35,6 +35,10 @@ def setUp(self): broker.declare_actor(actor_div) + def tearDown(self): + RemouladeInstrumentor().uninstrument() + super().tearDown() + def test_message(self): actor_div.send(2, 3) diff --git a/instrumentation/opentelemetry-instrumentation-requests/setup.cfg b/instrumentation/opentelemetry-instrumentation-requests/setup.cfg index 074978efad..b750920dea 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-requests/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 httpretty ~= 1.0 [options.packages.find] 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/setup.cfg b/instrumentation/opentelemetry-instrumentation-sklearn/setup.cfg index ce37af0098..d224af6d62 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-sklearn/setup.cfg @@ -28,24 +28,23 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 0eb5bcc268..b0ae442a0c 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg b/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg index fcc7ad333e..007a32860b 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg @@ -28,27 +28,26 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 packaging >= 21.0 wrapt >= 1.11.2 [options.extras_require] test = - opentelemetry-sdk ~= 1.3 + opentelemetry-sdk ~= 1.12 pytest [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py index bc438c609a..e56485ca77 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py @@ -22,6 +22,49 @@ .. _sqlalchemy: https://pypi.org/project/sqlalchemy/ +SQLCOMMENTER +**************************************** +You can optionally configure SQLAlchemy instrumentation to enable sqlcommenter which enriches +the query with contextual information. + +Usage +----- + +.. code:: python + + from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor + + SQLAlchemyInstrumentor().instrument(enable_commenter=True, commenter_options={}) + + +For example, +:: + + Invoking engine.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter is enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" + +SQLCommenter Configurations +*************************** +We can configure the tags to be appended to the sqlquery log by adding configuration inside commenter_options(default:{}) keyword + +db_driver = True(Default) or False + +For example, +:: +Enabling this flag will add any underlying driver like psycopg2 /*db_driver='psycopg2'*/ + +db_framework = True(Default) or False + +For example, +:: +Enabling this flag will add db_framework and it's version /*db_framework='sqlalchemy:0.41b0'*/ + +opentelemetry_values = True(Default) or False + +For example, +:: +Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ + Usage ----- .. code:: python @@ -115,6 +158,7 @@ def _instrument(self, **kwargs): _get_tracer(tracer_provider), kwargs.get("engine"), kwargs.get("enable_commenter", False), + kwargs.get("commenter_options", {}), ) if kwargs.get("engines") is not None and isinstance( kwargs.get("engines"), Sequence @@ -124,6 +168,7 @@ def _instrument(self, **kwargs): _get_tracer(tracer_provider), engine, kwargs.get("enable_commenter", False), + kwargs.get("commenter_options", {}), ) for engine in kwargs.get("engines") ] diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index 8121c99d13..7441c0aa03 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -21,11 +21,10 @@ ) from opentelemetry.instrumentation.sqlalchemy.version import __version__ from opentelemetry.instrumentation.utils import ( - _generate_opentelemetry_traceparent, - _generate_sql_comment, + _add_sql_comment, + _get_opentelemetry_values, ) from opentelemetry.semconv.trace import NetTransportValues, SpanAttributes -from opentelemetry.trace import Span from opentelemetry.trace.status import Status, StatusCode @@ -95,11 +94,14 @@ def _wrap_connect_internal(func, module, args, kwargs): class EngineTracer: - def __init__(self, tracer, engine, enable_commenter=False): + def __init__( + self, tracer, engine, enable_commenter=True, commenter_options=None + ): self.tracer = tracer self.engine = engine self.vendor = _normalize_vendor(engine.name) self.enable_commenter = enable_commenter + self.commenter_options = commenter_options if commenter_options else {} listen( engine, "before_cursor_execute", self._before_cur_exec, retval=True @@ -141,21 +143,29 @@ def _before_cur_exec( span.set_attribute(SpanAttributes.DB_SYSTEM, self.vendor) for key, value in attrs.items(): span.set_attribute(key, value) + if self.enable_commenter: + commenter_data = dict( + db_driver=conn.engine.driver, + # Driver/framework centric information. + db_framework=f"sqlalchemy:{__version__}", + ) + + if self.commenter_options.get("opentelemetry_values", True): + commenter_data.update(**_get_opentelemetry_values()) + + # Filter down to just the requested attributes. + commenter_data = { + k: v + for k, v in commenter_data.items() + if self.commenter_options.get(k, True) + } + + statement = _add_sql_comment(statement, **commenter_data) context._otel_span = span - if self.enable_commenter: - statement = statement + EngineTracer._generate_comment(span=span) return statement, params - @staticmethod - def _generate_comment(span: Span) -> str: - span_context = span.get_span_context() - meta = {} - if span_context.is_valid: - meta.update(_generate_opentelemetry_traceparent(span)) - return _generate_sql_comment(**meta) - # pylint: disable=unused-argument def _after_cur_exec(conn, cursor, statement, params, context, executemany): 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py index 0f45fa77eb..5fa74376f9 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio -import logging from unittest import mock import pytest @@ -21,7 +20,6 @@ from opentelemetry import trace from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor -from opentelemetry.instrumentation.sqlalchemy.engine import EngineTracer from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider, export from opentelemetry.test.test_base import TestBase @@ -217,22 +215,3 @@ async def run(): ) asyncio.get_event_loop().run_until_complete(run()) - - def test_generate_commenter(self): - logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) - engine = create_engine("sqlite:///:memory:") - SQLAlchemyInstrumentor().instrument( - engine=engine, - tracer_provider=self.tracer_provider, - enable_commenter=True, - ) - - cnx = engine.connect() - cnx.execute("SELECT 1 + 1;").fetchall() - spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 2) - span = spans[1] - self.assertIn( - EngineTracer._generate_comment(span), - self.caplog.records[-2].getMessage(), - ) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py index 89f8d4cca7..616388f5e5 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py @@ -11,6 +11,7 @@ # WITHOUT 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 logging import pytest from sqlalchemy import create_engine @@ -28,26 +29,28 @@ def tearDown(self): super().tearDown() SQLAlchemyInstrumentor().uninstrument() + def test_sqlcommenter_disabled(self): + logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) + engine = create_engine("sqlite:///:memory:", echo=True) + SQLAlchemyInstrumentor().instrument( + engine=engine, tracer_provider=self.tracer_provider + ) + cnx = engine.connect() + cnx.execute("SELECT 1;").fetchall() + + self.assertEqual(self.caplog.records[-2].getMessage(), "SELECT 1;") + def test_sqlcommenter_enabled(self): engine = create_engine("sqlite:///:memory:") SQLAlchemyInstrumentor().instrument( engine=engine, tracer_provider=self.tracer_provider, enable_commenter=True, + commenter_options={"db_framework": False}, ) cnx = engine.connect() cnx.execute("SELECT 1;").fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), - r"SELECT 1; /\*traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/", + r"SELECT 1 /\*db_driver='(.*)',traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", ) - - def test_sqlcommenter_disabled(self): - engine = create_engine("sqlite:///:memory:", echo=True) - SQLAlchemyInstrumentor().instrument( - engine=engine, tracer_provider=self.tracer_provider - ) - cnx = engine.connect() - cnx.execute("SELECT 1;").fetchall() - - self.assertEqual(self.caplog.records[-2].getMessage(), "SELECT 1;") diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg b/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg index 14ce6ce7d8..9d3e700efa 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg @@ -28,25 +28,24 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation-dbapi == 0.32b0 - opentelemetry-instrumentation == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation-dbapi == 0.33b0 + opentelemetry-instrumentation == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 d0074fee82..d67f786816 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.32b0" +__version__ = "0.33b0" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py b/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py index 714ca0ea02..581920232b 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py @@ -21,30 +21,26 @@ class TestSQLite3(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._connection2 = None - cls._cursor2 = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - SQLite3Instrumentor().instrument(tracer_provider=cls.tracer_provider) - cls._connection = sqlite3.connect(":memory:") - cls._cursor = cls._connection.cursor() - cls._connection2 = dbapi2.connect(":memory:") - cls._cursor2 = cls._connection2.cursor() + def setUp(self): + super().setUp() + SQLite3Instrumentor().instrument(tracer_provider=self.tracer_provider) + self._tracer = self.tracer_provider.get_tracer(__name__) + self._connection = sqlite3.connect(":memory:") + self._cursor = self._connection.cursor() + self._connection2 = dbapi2.connect(":memory:") + self._cursor2 = self._connection2.cursor() - @classmethod - def tearDownClass(cls): - if cls._cursor: - cls._cursor.close() - if cls._connection: - cls._connection.close() - if cls._cursor2: - cls._cursor2.close() - if cls._connection2: - cls._connection2.close() + def tearDown(self): + super().tearDown() + if self._cursor: + self._cursor.close() + if self._connection: + self._connection.close() + if self._cursor2: + self._cursor2.close() + if self._connection2: + self._connection2.close() + SQLite3Instrumentor().uninstrument() def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() @@ -65,6 +61,12 @@ def validate_spans(self, span_name): self.assertIs(child_span.parent, root_span.get_span_context()) self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT) + def _create_tables(self): + stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" + self._cursor.execute(stmt) + self._cursor2.execute(stmt) + self.memory_exporter.clear() + def test_execute(self): """Should create a child span for execute method""" stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" @@ -78,6 +80,9 @@ def test_execute(self): def test_executemany(self): """Should create a child span for executemany""" + self._create_tables() + + # real spans for executemany stmt = "INSERT INTO test (id) VALUES (?)" data = [("1",), ("2",), ("3",)] with self._tracer.start_as_current_span("rootSpan"): diff --git a/instrumentation/opentelemetry-instrumentation-starlette/LICENSE b/instrumentation/opentelemetry-instrumentation-starlette/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-starlette/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-starlette/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-starlette/MANIFEST.in new file mode 100644 index 0000000000..aed3e33273 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-starlette/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg b/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg index 4d20a8b2a0..d0f2826ce8 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg @@ -28,23 +28,22 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-instrumentation-asgi == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-instrumentation-asgi == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.entry_points] opentelemetry_instrumentor = @@ -52,7 +51,7 @@ opentelemetry_instrumentor = [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 requests ~= 2.23.0 # needed for testclient [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py index 259e054d32..110644cfb3 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py @@ -51,7 +51,7 @@ def home(request): ********************** Utilize request/response hooks to execute custom logic to be performed before/after performing a request. The server request hook takes in a server span and ASGI -scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method recieve is called. +scope object for every incoming request. The client request hook is called with the internal span and an ASGI scope which is sent as a dictionary for when the method receive is called. The client response hook is called with the internal span and an ASGI event which is sent as a dictionary for when the method send is called. .. code-block:: python 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py index 8c98feca4e..6f9a509450 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py @@ -95,7 +95,7 @@ def test_starlette_route_attribute_added(self): ) def test_starlette_excluded_urls(self): - """Ensure that givem starlette routes are excluded.""" + """Ensure that given starlette routes are excluded.""" self._client.get("/healthzz") spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg b/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg index dc62f6a546..4ea9772e36 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg @@ -28,14 +28,13 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: @@ -46,7 +45,7 @@ install_requires = [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg b/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg index 389f65c192..56418ffd3c 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg @@ -27,26 +27,25 @@ classifiers = Intended Audience :: Developers License :: OSI Approved :: Apache Software License Programming Language :: Python - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-instrumentation == 0.32b0 - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.entry_points] opentelemetry_instrumentor = 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 93e3dc8191..63e41a4574 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -156,6 +156,7 @@ def client_resposne_hook(span, future): from collections import namedtuple from functools import partial from logging import getLogger +from time import time_ns from typing import Collection from timeit import default_timer @@ -182,7 +183,6 @@ def client_resposne_hook(span, future): from opentelemetry.metrics import Histogram, get_meter from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status, StatusCode -from opentelemetry.util._time import _time_ns from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, @@ -225,7 +225,7 @@ def _instrument(self, **kwargs): perfectly on the other hand as it executes in the same context as on_finish and log_exection which are patched to finish a span after a request is served. - However, we cannot just patch RequestHandler's prepare method because it is supposed to be overwridden + However, we cannot just patch RequestHandler's prepare method because it is supposed to be overridden by sub-classes and since the parent prepare method does not do anything special, sub-classes don't have to call super() when overriding the method. diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/client.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/client.py index 79cf63cd0f..bd8b066fe5 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/client.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/client.py @@ -13,6 +13,7 @@ # limitations under the License. import functools +from time import time_ns from tornado.httpclient import HTTPError, HTTPRequest @@ -21,7 +22,6 @@ from opentelemetry.propagate import inject from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status -from opentelemetry.util._time import _time_ns from opentelemetry.util.http import remove_url_credentials 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-urllib/setup.cfg b/instrumentation/opentelemetry-instrumentation-urllib/setup.cfg index cc77e7f387..8993ee0f98 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-urllib/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 httpretty ~= 1.0 [options.packages.find] 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 d0074fee82..d67f786816 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.32b0" +__version__ = "0.33b0" _instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/setup.cfg b/instrumentation/opentelemetry-instrumentation-urllib3/setup.cfg index 0cb34fead1..2d28acbe75 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-urllib3/setup.cfg @@ -28,27 +28,26 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 wrapt >= 1.0.0, < 2.0.0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 httpretty ~= 1.0 [options.packages.find] diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index e4973613d1..f32e208ac6 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -66,6 +66,7 @@ def response_hook(span, request, response): import contextlib import typing +from timeit import default_timer from typing import Collection import urllib3.connectionpool @@ -83,9 +84,10 @@ def response_hook(span, request, response): http_status_to_status_code, unwrap, ) +from opentelemetry.metrics import Histogram, get_meter from opentelemetry.propagate import inject from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import Span, SpanKind, get_tracer +from opentelemetry.trace import Span, SpanKind, Tracer, get_tracer from opentelemetry.trace.status import Status from opentelemetry.util.http.httplib import set_ip_on_next_http_connection @@ -135,8 +137,31 @@ def _instrument(self, **kwargs): """ tracer_provider = kwargs.get("tracer_provider") tracer = get_tracer(__name__, __version__, tracer_provider) + + meter_provider = kwargs.get("meter_provider") + meter = get_meter(__name__, __version__, meter_provider) + + duration_histogram = meter.create_histogram( + name="http.client.duration", + unit="ms", + description="measures the duration outbound HTTP requests", + ) + request_size_histogram = meter.create_histogram( + name="http.client.request.size", + unit="By", + description="measures the size of HTTP request messages (compressed)", + ) + response_size_histogram = meter.create_histogram( + name="http.client.response.size", + unit="By", + description="measures the size of HTTP response messages (compressed)", + ) + _instrument( tracer, + duration_histogram, + request_size_histogram, + response_size_histogram, request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), url_filter=kwargs.get("url_filter"), @@ -147,7 +172,10 @@ def _uninstrument(self, **kwargs): def _instrument( - tracer, + tracer: Tracer, + duration_histogram: Histogram, + request_size_histogram: Histogram, + response_size_histogram: Histogram, request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, url_filter: _UrlFilterT = None, @@ -175,11 +203,30 @@ def instrumented_urlopen(wrapped, instance, args, kwargs): inject(headers) with _suppress_further_instrumentation(): + start_time = default_timer() response = wrapped(*args, **kwargs) + elapsed_time = round((default_timer() - start_time) * 1000) _apply_response(span, response) if callable(response_hook): response_hook(span, instance, response) + + request_size = 0 if body is None else len(body) + response_size = int(response.headers.get("Content-Length", 0)) + metric_attributes = _create_metric_attributes( + instance, response, method + ) + + duration_histogram.record( + elapsed_time, attributes=metric_attributes + ) + request_size_histogram.record( + request_size, attributes=metric_attributes + ) + response_size_histogram.record( + response_size, attributes=metric_attributes + ) + return response wrapt.wrap_function_wrapper( @@ -254,6 +301,29 @@ def _is_instrumentation_suppressed() -> bool: ) +def _create_metric_attributes( + instance: urllib3.connectionpool.HTTPConnectionPool, + response: urllib3.response.HTTPResponse, + method: str, +) -> dict: + metric_attributes = { + SpanAttributes.HTTP_METHOD: method, + SpanAttributes.HTTP_HOST: instance.host, + SpanAttributes.HTTP_SCHEME: instance.scheme, + SpanAttributes.HTTP_STATUS_CODE: response.status, + SpanAttributes.NET_PEER_NAME: instance.host, + SpanAttributes.NET_PEER_PORT: instance.port, + } + + version = getattr(response, "version") + if version: + metric_attributes[SpanAttributes.HTTP_FLAVOR] = ( + "1.1" if version == 11 else "1.0" + ) + + return metric_attributes + + @contextlib.contextmanager def _suppress_further_instrumentation(): token = context.attach( diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/package.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/package.py index 29ec682926..2f5df62de8 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/package.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/package.py @@ -14,3 +14,5 @@ _instruments = ("urllib3 >= 1.0.0, < 2.0.0",) + +_supports_metrics = True 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_ip_support.py b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_ip_support.py index 5baddee516..d47cd8f1ea 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_ip_support.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_ip_support.py @@ -12,8 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from timeit import default_timer + import urllib3 import urllib3.exceptions +from urllib3.request import encode_multipart_formdata from opentelemetry import trace from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor @@ -84,3 +87,136 @@ def assert_success_span( "net.peer.ip": self.assert_ip, } self.assertGreaterEqual(span.attributes.items(), attributes.items()) + + +class TestURLLib3InstrumentorMetric(HttpTestBase, TestBase): + def setUp(self): + super().setUp() + self.assert_ip = self.server.server_address[0] + self.assert_port = self.server.server_address[1] + self.http_host = ":".join(map(str, self.server.server_address[:2])) + self.http_url_base = "http://" + self.http_host + self.http_url = self.http_url_base + "/status/200" + URLLib3Instrumentor().instrument(meter_provider=self.meter_provider) + + def tearDown(self): + super().tearDown() + URLLib3Instrumentor().uninstrument() + + def test_metric_uninstrument(self): + with urllib3.PoolManager() as pool: + pool.request("GET", self.http_url) + URLLib3Instrumentor().uninstrument() + pool.request("GET", self.http_url) + + metrics_list = self.memory_metrics_reader.get_metrics_data() + for resource_metric in metrics_list.resource_metrics: + for scope_metric in resource_metric.scope_metrics: + for metric in scope_metric.metrics: + for point in list(metric.data.data_points): + self.assertEqual(point.count, 1) + + def test_basic_metric_check_client_size_get(self): + with urllib3.PoolManager() as pool: + start_time = default_timer() + response = pool.request("GET", self.http_url) + client_duration_estimated = (default_timer() - start_time) * 1000 + + expected_attributes = { + "http.status_code": 200, + "http.host": self.assert_ip, + "http.method": "GET", + "http.flavor": "1.1", + "http.scheme": "http", + "net.peer.name": self.assert_ip, + "net.peer.port": self.assert_port, + } + expected_data = { + "http.client.request.size": 0, + "http.client.response.size": len(response.data), + } + expected_metrics = [ + "http.client.duration", + "http.client.request.size", + "http.client.response.size", + ] + + resource_metrics = ( + self.memory_metrics_reader.get_metrics_data().resource_metrics + ) + for metrics in resource_metrics: + for scope_metrics in metrics.scope_metrics: + self.assertEqual(len(scope_metrics.metrics), 3) + for metric in scope_metrics.metrics: + for data_point in metric.data.data_points: + if metric.name in expected_data: + self.assertEqual( + data_point.sum, expected_data[metric.name] + ) + if metric.name == "http.client.duration": + self.assertAlmostEqual( + data_point.sum, + client_duration_estimated, + delta=1000, + ) + self.assertIn(metric.name, expected_metrics) + self.assertDictEqual( + expected_attributes, + dict(data_point.attributes), + ) + self.assertEqual(data_point.count, 1) + + def test_basic_metric_check_client_size_post(self): + with urllib3.PoolManager() as pool: + start_time = default_timer() + data_fields = {"data": "test"} + response = pool.request("POST", self.http_url, fields=data_fields) + client_duration_estimated = (default_timer() - start_time) * 1000 + + expected_attributes = { + "http.status_code": 501, + "http.host": self.assert_ip, + "http.method": "POST", + "http.flavor": "1.1", + "http.scheme": "http", + "net.peer.name": self.assert_ip, + "net.peer.port": self.assert_port, + } + + body = encode_multipart_formdata(data_fields)[0] + + expected_data = { + "http.client.request.size": len(body), + "http.client.response.size": len(response.data), + } + expected_metrics = [ + "http.client.duration", + "http.client.request.size", + "http.client.response.size", + ] + + resource_metrics = ( + self.memory_metrics_reader.get_metrics_data().resource_metrics + ) + for metrics in resource_metrics: + for scope_metrics in metrics.scope_metrics: + self.assertEqual(len(scope_metrics.metrics), 3) + for metric in scope_metrics.metrics: + for data_point in metric.data.data_points: + if metric.name in expected_data: + self.assertEqual( + data_point.sum, expected_data[metric.name] + ) + if metric.name == "http.client.duration": + self.assertAlmostEqual( + data_point.sum, + client_duration_estimated, + delta=1000, + ) + self.assertIn(metric.name, expected_metrics) + + self.assertDictEqual( + expected_attributes, + dict(data_point.attributes), + ) + self.assertEqual(data_point.count, 1) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg b/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg index 48f434aaed..fc4b2c5f99 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg @@ -28,26 +28,25 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.32b0 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-util-http == 0.32b0 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.33b0 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-util-http == 0.33b0 [options.extras_require] test = - opentelemetry-test-utils == 0.32b0 + opentelemetry-test-utils == 0.33b0 [options.packages.find] where = src 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 11c5acf643..70974b65a8 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -85,7 +85,7 @@ def GET(self): Request/Response hooks ********************** -Utilize request/reponse hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment. +Utilize request/response hooks to execute custom logic to be performed before/after performing a request. Environ is an instance of WSGIEnvironment. Response_headers is a list of key-value (tuples) representing the response headers returned from the response. .. code-block:: python @@ -334,6 +334,22 @@ 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_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 add_response_attributes( span, start_response_status, response_headers ): # pylint: disable=unused-argument @@ -436,15 +452,10 @@ def __call__(self, environ, start_response): start_response: The WSGI start_response callable. """ req_attrs = collect_request_attributes(environ) - 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] - - 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] + active_requests_count_attrs = _parse_active_request_count_attrs( + req_attrs + ) + duration_attrs = _parse_duration_attrs(req_attrs) span, token = _start_internal_or_server_span( tracer=self.tracer, 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index 7bdfabc37f..eeaad4c3cb 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -508,8 +508,7 @@ def test_mark_span_internal_in_presence_of_span_from_other_framework(self): class TestAdditionOfCustomRequestResponseHeaders(WsgiTestBase): def setUp(self): super().setUp() - tracer_provider, _ = TestBase.create_tracer_provider() - self.tracer = tracer_provider.get_tracer(__name__) + self.tracer = self.tracer_provider.get_tracer(__name__) def iterate_response(self, response): while True: diff --git a/opentelemetry-contrib-instrumentations/setup.cfg b/opentelemetry-contrib-instrumentations/setup.cfg index 89d2ea75db..520e0c62d8 100644 --- a/opentelemetry-contrib-instrumentations/setup.cfg +++ b/opentelemetry-contrib-instrumentations/setup.cfg @@ -14,61 +14,60 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir = =src packages = find_namespace: zip_safe = False include_package_data = True install_requires = - opentelemetry-instrumentation-aio-pika==0.32b0 - opentelemetry-instrumentation-aiohttp-client==0.32b0 - opentelemetry-instrumentation-aiopg==0.32b0 - opentelemetry-instrumentation-asgi==0.32b0 - opentelemetry-instrumentation-asyncpg==0.32b0 - opentelemetry-instrumentation-aws-lambda==0.32b0 - opentelemetry-instrumentation-boto==0.32b0 - opentelemetry-instrumentation-boto3sqs==0.32b0 - opentelemetry-instrumentation-botocore==0.32b0 - opentelemetry-instrumentation-celery==0.32b0 - opentelemetry-instrumentation-confluent-kafka==0.32b0 - opentelemetry-instrumentation-dbapi==0.32b0 - opentelemetry-instrumentation-django==0.32b0 - opentelemetry-instrumentation-elasticsearch==0.32b0 - opentelemetry-instrumentation-falcon==0.32b0 - opentelemetry-instrumentation-fastapi==0.32b0 - opentelemetry-instrumentation-flask==0.32b0 - opentelemetry-instrumentation-grpc==0.32b0 - opentelemetry-instrumentation-httpx==0.32b0 - opentelemetry-instrumentation-jinja2==0.32b0 - opentelemetry-instrumentation-kafka-python==0.32b0 - opentelemetry-instrumentation-logging==0.32b0 - opentelemetry-instrumentation-mysql==0.32b0 - opentelemetry-instrumentation-pika==0.32b0 - opentelemetry-instrumentation-psycopg2==0.32b0 - opentelemetry-instrumentation-pymemcache==0.32b0 - opentelemetry-instrumentation-pymongo==0.32b0 - opentelemetry-instrumentation-pymysql==0.32b0 - opentelemetry-instrumentation-pyramid==0.32b0 - opentelemetry-instrumentation-redis==0.32b0 - opentelemetry-instrumentation-remoulade==0.32b0 - opentelemetry-instrumentation-requests==0.32b0 - opentelemetry-instrumentation-sklearn==0.32b0 - opentelemetry-instrumentation-sqlalchemy==0.32b0 - opentelemetry-instrumentation-sqlite3==0.32b0 - opentelemetry-instrumentation-starlette==0.32b0 - opentelemetry-instrumentation-system-metrics==0.32b0 - opentelemetry-instrumentation-tornado==0.32b0 - opentelemetry-instrumentation-urllib==0.32b0 - opentelemetry-instrumentation-urllib3==0.32b0 - opentelemetry-instrumentation-wsgi==0.32b0 + opentelemetry-instrumentation-aio-pika==0.33b0 + opentelemetry-instrumentation-aiohttp-client==0.33b0 + opentelemetry-instrumentation-aiopg==0.33b0 + opentelemetry-instrumentation-asgi==0.33b0 + opentelemetry-instrumentation-asyncpg==0.33b0 + opentelemetry-instrumentation-aws-lambda==0.33b0 + opentelemetry-instrumentation-boto==0.33b0 + opentelemetry-instrumentation-boto3sqs==0.33b0 + opentelemetry-instrumentation-botocore==0.33b0 + opentelemetry-instrumentation-celery==0.33b0 + opentelemetry-instrumentation-confluent-kafka==0.33b0 + opentelemetry-instrumentation-dbapi==0.33b0 + opentelemetry-instrumentation-django==0.33b0 + opentelemetry-instrumentation-elasticsearch==0.33b0 + opentelemetry-instrumentation-falcon==0.33b0 + opentelemetry-instrumentation-fastapi==0.33b0 + opentelemetry-instrumentation-flask==0.33b0 + opentelemetry-instrumentation-grpc==0.33b0 + opentelemetry-instrumentation-httpx==0.33b0 + opentelemetry-instrumentation-jinja2==0.33b0 + opentelemetry-instrumentation-kafka-python==0.33b0 + opentelemetry-instrumentation-logging==0.33b0 + opentelemetry-instrumentation-mysql==0.33b0 + opentelemetry-instrumentation-pika==0.33b0 + opentelemetry-instrumentation-psycopg2==0.33b0 + opentelemetry-instrumentation-pymemcache==0.33b0 + opentelemetry-instrumentation-pymongo==0.33b0 + opentelemetry-instrumentation-pymysql==0.33b0 + opentelemetry-instrumentation-pyramid==0.33b0 + opentelemetry-instrumentation-redis==0.33b0 + opentelemetry-instrumentation-remoulade==0.33b0 + opentelemetry-instrumentation-requests==0.33b0 + opentelemetry-instrumentation-sklearn==0.33b0 + opentelemetry-instrumentation-sqlalchemy==0.33b0 + opentelemetry-instrumentation-sqlite3==0.33b0 + opentelemetry-instrumentation-starlette==0.33b0 + opentelemetry-instrumentation-system-metrics==0.33b0 + opentelemetry-instrumentation-tornado==0.33b0 + opentelemetry-instrumentation-urllib==0.33b0 + opentelemetry-instrumentation-urllib3==0.33b0 + opentelemetry-instrumentation-wsgi==0.33b0 [options.packages.find] where = src diff --git a/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py b/opentelemetry-contrib-instrumentations/src/opentelemetry/contrib-instrumentations/version.py index 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/opentelemetry-distro/setup.cfg b/opentelemetry-distro/setup.cfg index f13ef4d8a3..845a1f21d1 100644 --- a/opentelemetry-distro/setup.cfg +++ b/opentelemetry-distro/setup.cfg @@ -28,22 +28,21 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Typing :: Typed [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: zip_safe = False include_package_data = True install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-instrumentation == 0.32b0 - opentelemetry-sdk == 1.12.0rc2 + opentelemetry-api ~= 1.12 + opentelemetry-instrumentation == 0.33b0 + opentelemetry-sdk == 1.12.0 [options.packages.find] where = src @@ -57,4 +56,4 @@ opentelemetry_configurator = [options.extras_require] test = otlp = - opentelemetry-exporter-otlp == 1.12.0rc2 + opentelemetry-exporter-otlp == 1.12.0 diff --git a/opentelemetry-distro/src/opentelemetry/distro/version.py b/opentelemetry-distro/src/opentelemetry/distro/version.py index 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/opentelemetry-instrumentation/README.rst b/opentelemetry-instrumentation/README.rst index 96e44a8496..a93bedcc27 100644 --- a/opentelemetry-instrumentation/README.rst +++ b/opentelemetry-instrumentation/README.rst @@ -51,7 +51,7 @@ and when possible, apply automatic tracing instrumentation on them. This means y will get automatic distributed tracing for free without having to make any code changes at all. This will also configure a global tracer and tracing exporter without you having to make any code changes. By default, the instrument command will use the OTLP exporter but -this can be overriden when needed. +this can be overridden when needed. The command supports the following configuration options as CLI arguments and environment vars: diff --git a/opentelemetry-instrumentation/setup.cfg b/opentelemetry-instrumentation/setup.cfg index 57f7936b42..c0eda1876d 100644 --- a/opentelemetry-instrumentation/setup.cfg +++ b/opentelemetry-instrumentation/setup.cfg @@ -28,14 +28,13 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 17cb83180c..5305b7e10e 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -18,150 +18,150 @@ libraries = { "aio_pika": { "library": "aio_pika ~= 7.2.0", - "instrumentation": "opentelemetry-instrumentation-aio-pika==0.32b0", + "instrumentation": "opentelemetry-instrumentation-aio-pika==0.33b0", }, "aiohttp": { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.32b0", + "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.33b0", }, "aiopg": { "library": "aiopg >= 0.13.0, < 1.3.0", - "instrumentation": "opentelemetry-instrumentation-aiopg==0.32b0", + "instrumentation": "opentelemetry-instrumentation-aiopg==0.33b0", }, "asgiref": { "library": "asgiref ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-asgi==0.32b0", + "instrumentation": "opentelemetry-instrumentation-asgi==0.33b0", }, "asyncpg": { "library": "asyncpg >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-asyncpg==0.32b0", + "instrumentation": "opentelemetry-instrumentation-asyncpg==0.33b0", }, "boto": { "library": "boto~=2.0", - "instrumentation": "opentelemetry-instrumentation-boto==0.32b0", + "instrumentation": "opentelemetry-instrumentation-boto==0.33b0", }, "boto3": { "library": "boto3 ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.32b0", + "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.33b0", }, "botocore": { "library": "botocore ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-botocore==0.32b0", + "instrumentation": "opentelemetry-instrumentation-botocore==0.33b0", }, "celery": { "library": "celery >= 4.0, < 6.0", - "instrumentation": "opentelemetry-instrumentation-celery==0.32b0", + "instrumentation": "opentelemetry-instrumentation-celery==0.33b0", }, "confluent-kafka": { "library": "confluent-kafka ~= 1.8.2", - "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.32b0", + "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.33b0", }, "django": { "library": "django >= 1.10", - "instrumentation": "opentelemetry-instrumentation-django==0.32b0", + "instrumentation": "opentelemetry-instrumentation-django==0.33b0", }, "elasticsearch": { "library": "elasticsearch >= 2.0", - "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.32b0", + "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.33b0", }, "falcon": { "library": "falcon >= 1.4.1, < 4.0.0", - "instrumentation": "opentelemetry-instrumentation-falcon==0.32b0", + "instrumentation": "opentelemetry-instrumentation-falcon==0.33b0", }, "fastapi": { "library": "fastapi ~= 0.58", - "instrumentation": "opentelemetry-instrumentation-fastapi==0.32b0", + "instrumentation": "opentelemetry-instrumentation-fastapi==0.33b0", }, "flask": { "library": "flask >= 1.0, < 3.0", - "instrumentation": "opentelemetry-instrumentation-flask==0.32b0", + "instrumentation": "opentelemetry-instrumentation-flask==0.33b0", }, "grpcio": { "library": "grpcio ~= 1.27", - "instrumentation": "opentelemetry-instrumentation-grpc==0.32b0", + "instrumentation": "opentelemetry-instrumentation-grpc==0.33b0", }, "httpx": { "library": "httpx >= 0.18.0", - "instrumentation": "opentelemetry-instrumentation-httpx==0.32b0", + "instrumentation": "opentelemetry-instrumentation-httpx==0.33b0", }, "jinja2": { "library": "jinja2 >= 2.7, < 4.0", - "instrumentation": "opentelemetry-instrumentation-jinja2==0.32b0", + "instrumentation": "opentelemetry-instrumentation-jinja2==0.33b0", }, "kafka-python": { "library": "kafka-python >= 2.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.32b0", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.33b0", }, "mysql-connector-python": { "library": "mysql-connector-python ~= 8.0", - "instrumentation": "opentelemetry-instrumentation-mysql==0.32b0", + "instrumentation": "opentelemetry-instrumentation-mysql==0.33b0", }, "pika": { "library": "pika >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-pika==0.32b0", + "instrumentation": "opentelemetry-instrumentation-pika==0.33b0", }, "psycopg2": { "library": "psycopg2 >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.32b0", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.33b0", }, "pymemcache": { "library": "pymemcache >= 1.3.5, < 4", - "instrumentation": "opentelemetry-instrumentation-pymemcache==0.32b0", + "instrumentation": "opentelemetry-instrumentation-pymemcache==0.33b0", }, "pymongo": { "library": "pymongo >= 3.1, < 5.0", - "instrumentation": "opentelemetry-instrumentation-pymongo==0.32b0", + "instrumentation": "opentelemetry-instrumentation-pymongo==0.33b0", }, "PyMySQL": { "library": "PyMySQL < 2", - "instrumentation": "opentelemetry-instrumentation-pymysql==0.32b0", + "instrumentation": "opentelemetry-instrumentation-pymysql==0.33b0", }, "pyramid": { "library": "pyramid >= 1.7", - "instrumentation": "opentelemetry-instrumentation-pyramid==0.32b0", + "instrumentation": "opentelemetry-instrumentation-pyramid==0.33b0", }, "redis": { "library": "redis >= 2.6", - "instrumentation": "opentelemetry-instrumentation-redis==0.32b0", + "instrumentation": "opentelemetry-instrumentation-redis==0.33b0", }, "remoulade": { "library": "remoulade >= 0.50", - "instrumentation": "opentelemetry-instrumentation-remoulade==0.32b0", + "instrumentation": "opentelemetry-instrumentation-remoulade==0.33b0", }, "requests": { "library": "requests ~= 2.0", - "instrumentation": "opentelemetry-instrumentation-requests==0.32b0", + "instrumentation": "opentelemetry-instrumentation-requests==0.33b0", }, "scikit-learn": { "library": "scikit-learn ~= 0.24.0", - "instrumentation": "opentelemetry-instrumentation-sklearn==0.32b0", + "instrumentation": "opentelemetry-instrumentation-sklearn==0.33b0", }, "sqlalchemy": { "library": "sqlalchemy", - "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.32b0", + "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.33b0", }, "starlette": { "library": "starlette ~= 0.13.0", - "instrumentation": "opentelemetry-instrumentation-starlette==0.32b0", + "instrumentation": "opentelemetry-instrumentation-starlette==0.33b0", }, "psutil": { "library": "psutil >= 5", - "instrumentation": "opentelemetry-instrumentation-system-metrics==0.32b0", + "instrumentation": "opentelemetry-instrumentation-system-metrics==0.33b0", }, "tornado": { "library": "tornado >= 5.1.1", - "instrumentation": "opentelemetry-instrumentation-tornado==0.32b0", + "instrumentation": "opentelemetry-instrumentation-tornado==0.33b0", }, "urllib3": { "library": "urllib3 >= 1.0.0, < 2.0.0", - "instrumentation": "opentelemetry-instrumentation-urllib3==0.32b0", + "instrumentation": "opentelemetry-instrumentation-urllib3==0.33b0", }, } default_instrumentations = [ - "opentelemetry-instrumentation-aws-lambda==0.32b0", - "opentelemetry-instrumentation-dbapi==0.32b0", - "opentelemetry-instrumentation-logging==0.32b0", - "opentelemetry-instrumentation-sqlite3==0.32b0", - "opentelemetry-instrumentation-urllib==0.32b0", - "opentelemetry-instrumentation-wsgi==0.32b0", + "opentelemetry-instrumentation-aws-lambda==0.33b0", + "opentelemetry-instrumentation-dbapi==0.33b0", + "opentelemetry-instrumentation-logging==0.33b0", + "opentelemetry-instrumentation-sqlite3==0.33b0", + "opentelemetry-instrumentation-urllib==0.33b0", + "opentelemetry-instrumentation-wsgi==0.33b0", ] diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py index 181d5b6fce..95a943afb3 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/utils.py @@ -24,7 +24,7 @@ # pylint: disable=E0611 from opentelemetry.context import _SUPPRESS_INSTRUMENTATION_KEY # noqa: F401 from opentelemetry.propagate import extract -from opentelemetry.trace import Span, StatusCode +from opentelemetry.trace import StatusCode from opentelemetry.trace.propagation.tracecontext import ( TraceContextTextMapPropagator, ) @@ -147,7 +147,7 @@ def _generate_sql_comment(**meta) -> str: ) -def _url_quote(s): # pylint: disable=invalid-name +def _url_quote(s) -> str: # pylint: disable=invalid-name if not isinstance(s, (str, bytes)): return s quoted = urllib.parse.quote(s) @@ -158,7 +158,7 @@ def _url_quote(s): # pylint: disable=invalid-name return quoted.replace("%", "%%") -def _get_opentelemetry_values(): +def _get_opentelemetry_values() -> dict: """ Return the OpenTelemetry Trace and Span IDs if Span ID is set in the OpenTelemetry execution context. @@ -169,20 +169,22 @@ def _get_opentelemetry_values(): return _headers -def _generate_opentelemetry_traceparent(span: Span) -> str: - meta = {} - _version = "00" - _span_id = trace.format_span_id(span.context.span_id) - _trace_id = trace.format_trace_id(span.context.trace_id) - _flags = str(trace.TraceFlags.SAMPLED) - _traceparent = _version + "-" + _trace_id + "-" + _span_id + "-" + _flags - meta.update({"traceparent": _traceparent}) - return meta - - def _python_path_without_directory(python_path, directory, path_separator): return sub( rf"{escape(directory)}{path_separator}(?!$)", "", python_path, ) + + +def _add_sql_comment(sql, **meta) -> str: + """ + Appends comments to the sql statement and returns it + """ + comment = _generate_sql_comment(**meta) + sql = sql.rstrip() + if sql[-1] == ";": + sql = sql[:-1] + comment + ";" + else: + sql = sql + comment + return sql diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/version.py index 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/opentelemetry-instrumentation/tests/test_dependencies.py b/opentelemetry-instrumentation/tests/test_dependencies.py index a8acac62f4..04bcf476ea 100644 --- a/opentelemetry-instrumentation/tests/test_dependencies.py +++ b/opentelemetry-instrumentation/tests/test_dependencies.py @@ -26,9 +26,6 @@ class TestDependencyConflicts(TestBase): - def setUp(self): - pass - def test_get_dependency_conflicts_empty(self): self.assertIsNone(get_dependency_conflicts([])) diff --git a/opentelemetry-instrumentation/tests/test_propagators.py b/opentelemetry-instrumentation/tests/test_propagators.py index 62461aafa9..00ec65a128 100644 --- a/opentelemetry-instrumentation/tests/test_propagators.py +++ b/opentelemetry-instrumentation/tests/test_propagators.py @@ -14,6 +14,8 @@ # pylint: disable=protected-access +import unittest + from opentelemetry import trace from opentelemetry.instrumentation import propagators from opentelemetry.instrumentation.propagators import ( @@ -39,7 +41,7 @@ def test_get_set(self): propagators._RESPONSE_PROPAGATOR = original -class TestDictHeaderSetter(TestBase): +class TestDictHeaderSetter(unittest.TestCase): def test_simple(self): setter = DictHeaderSetter() carrier = {} diff --git a/opentelemetry-instrumentation/tests/test_utils.py b/opentelemetry-instrumentation/tests/test_utils.py index b7c9ecdc6e..3fd52ea7c6 100644 --- a/opentelemetry-instrumentation/tests/test_utils.py +++ b/opentelemetry-instrumentation/tests/test_utils.py @@ -12,17 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import unittest from http import HTTPStatus from opentelemetry.instrumentation.utils import ( + _add_sql_comment, _python_path_without_directory, http_status_to_status_code, ) -from opentelemetry.test.test_base import TestBase from opentelemetry.trace import StatusCode -class TestUtils(TestBase): +class TestUtils(unittest.TestCase): # See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#status def test_http_status_to_status_code(self): for status_code, expected in ( @@ -152,3 +153,36 @@ def test_remove_current_directory_from_python_path_linux_only_path(self): python_path, directory, path_separator ) self.assertEqual(actual_python_path, python_path) + + def test_add_sql_comments_with_semicolon(self): + sql_query_without_semicolon = "Select 1;" + comments = {"comment_1": "value 1", "comment 2": "value 3"} + commented_sql_without_semicolon = _add_sql_comment( + sql_query_without_semicolon, **comments + ) + + self.assertEqual( + commented_sql_without_semicolon, + "Select 1 /*comment%%202='value%%203',comment_1='value%%201'*/;", + ) + + def test_add_sql_comments_without_semicolon(self): + sql_query_without_semicolon = "Select 1" + comments = {"comment_1": "value 1", "comment 2": "value 3"} + commented_sql_without_semicolon = _add_sql_comment( + sql_query_without_semicolon, **comments + ) + + self.assertEqual( + commented_sql_without_semicolon, + "Select 1 /*comment%%202='value%%203',comment_1='value%%201'*/", + ) + + def test_add_sql_comments_without_comments(self): + sql_query_without_semicolon = "Select 1" + comments = {} + commented_sql_without_semicolon = _add_sql_comment( + sql_query_without_semicolon, **comments + ) + + self.assertEqual(commented_sql_without_semicolon, "Select 1") diff --git a/propagator/opentelemetry-propagator-aws-xray/setup.cfg b/propagator/opentelemetry-propagator-aws-xray/setup.cfg index 171abb55f4..f4afe67cad 100644 --- a/propagator/opentelemetry-propagator-aws-xray/setup.cfg +++ b/propagator/opentelemetry-propagator-aws-xray/setup.cfg @@ -28,19 +28,18 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 + opentelemetry-api ~= 1.12 [options.entry_points] opentelemetry_propagator = diff --git a/propagator/opentelemetry-propagator-ot-trace/setup.cfg b/propagator/opentelemetry-propagator-ot-trace/setup.cfg index c5ebbfdeac..5283c63b86 100644 --- a/propagator/opentelemetry-propagator-ot-trace/setup.cfg +++ b/propagator/opentelemetry-propagator-ot-trace/setup.cfg @@ -28,20 +28,19 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-sdk ~= 1.3 + opentelemetry-api ~= 1.12 + opentelemetry-sdk ~= 1.12 [options.packages.find] where = src 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/scripts/build_a_package.sh b/scripts/build_a_package.sh index 3920201191..1df97a26db 100755 --- a/scripts/build_a_package.sh +++ b/scripts/build_a_package.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This script builds wheels for a single package when trigged from a push to +# This script builds wheels for a single package when triggered from a push to # a tag as part of a GitHub workflow (See .github/publish-a-package.yml). The # wheel is then published to PyPI. diff --git a/scripts/eachdist.py b/scripts/eachdist.py index f67ce405fe..103a63de88 100755 --- a/scripts/eachdist.py +++ b/scripts/eachdist.py @@ -550,7 +550,7 @@ def update_changelog(path, version, new_entry): text = changelog.read() if f"## [{version}]" in text: raise AttributeError( - f"{path} already contans version {version}" + f"{path} already contains version {version}" ) with open(path, encoding="utf-8") as changelog: for line in changelog: diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/setup.cfg b/sdk-extension/opentelemetry-sdk-extension-aws/setup.cfg index ef1fa1f85b..ae53ace3ea 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/setup.cfg +++ b/sdk-extension/opentelemetry-sdk-extension-aws/setup.cfg @@ -28,19 +28,18 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: install_requires = - opentelemetry-sdk ~= 1.3 + opentelemetry-sdk ~= 1.12 [options.entry_points] opentelemetry_id_generator = diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/_lambda.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/_lambda.py index 762725325c..6f8fe68048 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/_lambda.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/_lambda.py @@ -29,7 +29,7 @@ class AwsLambdaResourceDetector(ResourceDetector): """Detects attribute values only available when the app is running on AWS Lambda and returns them in a Resource. - Uses Lambda defined runtime enivronment variables. See more: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime + Uses Lambda defined runtime environment variables. See more: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime """ def detect(self) -> "Resource": diff --git a/tests/opentelemetry-docker-tests/tests/asyncpg/test_asyncpg_functional.py b/tests/opentelemetry-docker-tests/tests/asyncpg/test_asyncpg_functional.py index 9470f68b05..8111bce15e 100644 --- a/tests/opentelemetry-docker-tests/tests/asyncpg/test_asyncpg_functional.py +++ b/tests/opentelemetry-docker-tests/tests/asyncpg/test_asyncpg_functional.py @@ -21,14 +21,11 @@ def async_call(coro): class TestFunctionalAsyncPG(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - AsyncPGInstrumentor().instrument(tracer_provider=cls.tracer_provider) - cls._connection = async_call( + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + AsyncPGInstrumentor().instrument(tracer_provider=self.tracer_provider) + self._connection = async_call( asyncpg.connect( database=POSTGRES_DB_NAME, user=POSTGRES_USER, @@ -38,9 +35,9 @@ def setUpClass(cls): ) ) - @classmethod - def tearDownClass(cls): + def tearDown(self): AsyncPGInstrumentor().uninstrument() + super().tearDown() def check_span(self, span): self.assertEqual( @@ -148,16 +145,13 @@ def test_instrumented_method_doesnt_capture_parameters(self, *_, **__): class TestFunctionalAsyncPG_CaptureParameters(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) AsyncPGInstrumentor(capture_parameters=True).instrument( - tracer_provider=cls.tracer_provider + tracer_provider=self.tracer_provider ) - cls._connection = async_call( + self._connection = async_call( asyncpg.connect( database=POSTGRES_DB_NAME, user=POSTGRES_USER, @@ -167,9 +161,9 @@ def setUpClass(cls): ) ) - @classmethod - def tearDownClass(cls): + def tearDown(self): AsyncPGInstrumentor().uninstrument() + super().tearDown() def check_span(self, span): self.assertEqual( diff --git a/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py b/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py index 59cf401e03..4f1305e866 100644 --- a/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py +++ b/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py @@ -29,22 +29,10 @@ class TestFunctionalMysql(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - MySQLInstrumentor().instrument() - - @classmethod - def tearDownClass(cls): - if cls._connection: - cls._connection.close() - MySQLInstrumentor().uninstrument() - def setUp(self): super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + MySQLInstrumentor().instrument() self._connection = mysql.connector.connect( user=MYSQL_USER, password=MYSQL_PASSWORD, @@ -54,6 +42,12 @@ def setUp(self): ) self._cursor = self._connection.cursor() + def tearDown(self): + self._cursor.close() + self._connection.close() + MySQLInstrumentor().uninstrument() + super().tearDown() + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py b/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py index 5f1d20bdc1..8157c06a32 100644 --- a/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py +++ b/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py @@ -36,14 +36,11 @@ def async_call(coro): class TestFunctionalAiopgConnect(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - AiopgInstrumentor().instrument(tracer_provider=cls.tracer_provider) - cls._connection = async_call( + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + AiopgInstrumentor().instrument(tracer_provider=self.tracer_provider) + self._connection = async_call( aiopg.connect( dbname=POSTGRES_DB_NAME, user=POSTGRES_USER, @@ -52,15 +49,13 @@ def setUpClass(cls): port=POSTGRES_PORT, ) ) - cls._cursor = async_call(cls._connection.cursor()) - - @classmethod - def tearDownClass(cls): - if cls._cursor: - cls._cursor.close() - if cls._connection: - cls._connection.close() + self._cursor = async_call(self._connection.cursor()) + + def tearDown(self): + self._cursor.close() + self._connection.close() AiopgInstrumentor().uninstrument() + super().tearDown() def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() @@ -121,18 +116,15 @@ def test_callproc(self): class TestFunctionalAiopgCreatePool(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - AiopgInstrumentor().instrument(tracer_provider=cls.tracer_provider) - cls._dsn = ( + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + AiopgInstrumentor().instrument(tracer_provider=self.tracer_provider) + self._dsn = ( f"dbname='{POSTGRES_DB_NAME}' user='{POSTGRES_USER}' password='{POSTGRES_PASSWORD}'" f" host='{POSTGRES_HOST}' port='{POSTGRES_PORT}'" ) - cls._pool = async_call( + self._pool = async_call( aiopg.create_pool( dbname=POSTGRES_DB_NAME, user=POSTGRES_USER, @@ -141,18 +133,15 @@ def setUpClass(cls): port=POSTGRES_PORT, ) ) - cls._connection = async_call(cls._pool.acquire()) - cls._cursor = async_call(cls._connection.cursor()) - - @classmethod - def tearDownClass(cls): - if cls._cursor: - cls._cursor.close() - if cls._connection: - cls._connection.close() - if cls._pool: - cls._pool.close() + self._connection = async_call(self._pool.acquire()) + self._cursor = async_call(self._connection.cursor()) + + def tearDown(self): + self._cursor.close() + self._connection.close() + self._pool.close() AiopgInstrumentor().uninstrument() + super().tearDown() def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py index 38ecff02e7..53112a5dbd 100644 --- a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py +++ b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py @@ -30,30 +30,25 @@ class TestFunctionalPsycopg(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) - Psycopg2Instrumentor().instrument(tracer_provider=cls.tracer_provider) - cls._connection = psycopg2.connect( + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + Psycopg2Instrumentor().instrument(tracer_provider=self.tracer_provider) + self._connection = psycopg2.connect( dbname=POSTGRES_DB_NAME, user=POSTGRES_USER, password=POSTGRES_PASSWORD, host=POSTGRES_HOST, port=POSTGRES_PORT, ) - cls._connection.set_session(autocommit=True) - cls._cursor = cls._connection.cursor() - - @classmethod - def tearDownClass(cls): - if cls._cursor: - cls._cursor.close() - if cls._connection: - cls._connection.close() + self._connection.set_session(autocommit=True) + self._cursor = self._connection.cursor() + + def tearDown(self): + self._cursor.close() + self._connection.close() Psycopg2Instrumentor().uninstrument() + super().tearDown() def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py index 1e3460600e..0dee17f865 100644 --- a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py +++ b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py @@ -26,34 +26,29 @@ class TestFunctionalPsycopg(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) Psycopg2Instrumentor().instrument(enable_commenter=True) - cls._connection = psycopg2.connect( + self._connection = psycopg2.connect( dbname=POSTGRES_DB_NAME, user=POSTGRES_USER, password=POSTGRES_PASSWORD, host=POSTGRES_HOST, port=POSTGRES_PORT, ) - cls._connection.set_session(autocommit=True) - cls._cursor = cls._connection.cursor() + self._connection.set_session(autocommit=True) + self._cursor = self._connection.cursor() - @classmethod - def tearDownClass(cls): - if cls._cursor: - cls._cursor.close() - if cls._connection: - cls._connection.close() + def tearDown(self): + self._cursor.close() + self._connection.close() Psycopg2Instrumentor().uninstrument() + super().tearDown() def test_commenter_enabled(self): self._cursor.execute("SELECT 1;") self.assertRegex( self._cursor.query.decode("ascii"), - r"SELECT 1; /\*traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/", + r"SELECT 1 /\*db_driver='psycopg2(.*)',dbapi_level='\d.\d',dbapi_threadsafety=\d,driver_paramstyle=(.*),libpq_version=\d*,traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", ) diff --git a/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py b/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py index a716cd8def..92c694953b 100644 --- a/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py +++ b/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py @@ -28,16 +28,21 @@ class TestFunctionalPymongo(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._tracer = cls.tracer_provider.get_tracer(__name__) - PymongoInstrumentor().instrument() + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) + self.instrumentor = PymongoInstrumentor() + self.instrumentor.instrument() + self.instrumentor._commandtracer_instance._tracer = self._tracer client = MongoClient( MONGODB_HOST, MONGODB_PORT, serverSelectionTimeoutMS=2000 ) db = client[MONGODB_DB_NAME] - cls._collection = db[MONGODB_COLLECTION_NAME] + self._collection = db[MONGODB_COLLECTION_NAME] + + def tearDown(self): + self.instrumentor.uninstrument() + super().tearDown() def validate_spans(self): spans = self.memory_exporter.get_finished_spans() diff --git a/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py b/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py index 881ef05d2a..83f7abf281 100644 --- a/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py +++ b/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py @@ -29,27 +29,24 @@ class TestFunctionalPyMysql(TestBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls._connection = None - cls._cursor = None - cls._tracer = cls.tracer_provider.get_tracer(__name__) + def setUp(self): + super().setUp() + self._tracer = self.tracer_provider.get_tracer(__name__) PyMySQLInstrumentor().instrument() - cls._connection = pymy.connect( + self._connection = pymy.connect( user=MYSQL_USER, password=MYSQL_PASSWORD, host=MYSQL_HOST, port=MYSQL_PORT, database=MYSQL_DB_NAME, ) - cls._cursor = cls._connection.cursor() + self._cursor = self._connection.cursor() - @classmethod - def tearDownClass(cls): - if cls._connection: - cls._connection.close() + def tearDown(self): + self._cursor.close() + self._connection.close() PyMySQLInstrumentor().uninstrument() + super().tearDown() def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() diff --git a/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py b/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py index 6a4ef5021c..21d7e36b00 100644 --- a/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py +++ b/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py @@ -31,8 +31,8 @@ def setUp(self): RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) def tearDown(self): - super().tearDown() RedisInstrumentor().uninstrument() + super().tearDown() def _check_span(self, span, name): self.assertEqual(span.name, name) @@ -203,8 +203,8 @@ def setUp(self): RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) def tearDown(self): - super().tearDown() RedisInstrumentor().uninstrument() + super().tearDown() def _check_span(self, span, name): self.assertEqual(span.name, name) @@ -383,8 +383,8 @@ def setUp(self): RedisInstrumentor().instrument(tracer_provider=self.tracer_provider) def tearDown(self): - super().tearDown() RedisInstrumentor().uninstrument() + super().tearDown() def _check_span(self, span, name): self.assertEqual(span.name, name) diff --git a/tests/opentelemetry-docker-tests/tests/sqlalchemy_tests/test_instrument.py b/tests/opentelemetry-docker-tests/tests/sqlalchemy_tests/test_instrument.py index 8c97d100e0..48944d58e0 100644 --- a/tests/opentelemetry-docker-tests/tests/sqlalchemy_tests/test_instrument.py +++ b/tests/opentelemetry-docker-tests/tests/sqlalchemy_tests/test_instrument.py @@ -35,6 +35,7 @@ class SQLAlchemyInstrumentTestCase(TestBase): """ def setUp(self): + super().setUp() # create a traced engine with the given arguments SQLAlchemyInstrumentor().instrument() dsn = ( @@ -45,23 +46,23 @@ def setUp(self): # prepare a connection self.conn = self.engine.connect() - super().setUp() def tearDown(self): # clear the database and dispose the engine self.conn.close() self.engine.dispose() SQLAlchemyInstrumentor().uninstrument() + super().tearDown() def test_engine_traced(self): # ensures that the engine is traced rows = self.conn.execute("SELECT").fetchall() self.assertEqual(len(rows), 1) - traces = self.memory_exporter.get_finished_spans() + spans = self.memory_exporter.get_finished_spans() # trace composition - self.assertEqual(len(traces), 1) - span = traces[0] + self.assertEqual(len(spans), 2) + span = spans[1] # check subset of span fields self.assertEqual(span.name, "SELECT opentelemetry-tests") self.assertIs(span.status.status_code, trace.StatusCode.UNSET) diff --git a/tox.ini b/tox.ini index 64210a8c0c..a4cea4a49a 100644 --- a/tox.ini +++ b/tox.ini @@ -6,151 +6,153 @@ envlist = ; for specifying supported Python versions per package. ; opentelemetry-sdk-extension-aws - py3{6,7,8,9,10}-test-sdkextension-aws + py3{7,8,9,10}-test-sdkextension-aws pypy3-test-sdkextension-aws ; opentelemetry-distro - py3{6,7,8,9,10}-test-distro + py3{7,8,9,10}-test-distro pypy3-test-distro ; opentelemetry-instrumentation - py3{6,7,8,9,10}-test-opentelemetry-instrumentation + py3{7,8,9,10}-test-opentelemetry-instrumentation pypy3-test-opentelemetry-instrumentation ; opentelemetry-instrumentation-aiohttp-client - py3{6,7,8,9,10}-test-instrumentation-aiohttp-client + py3{7,8,9,10}-test-instrumentation-aiohttp-client pypy3-test-instrumentation-aiohttp-client ; opentelemetry-instrumentation-aiopg - py3{6,7,8,9,10}-test-instrumentation-aiopg + py3{7,8,9,10}-test-instrumentation-aiopg ; instrumentation-aiopg intentionally excluded from pypy3 ; opentelemetry-instrumentation-aws-lambda - py3{6,7,8,9}-test-instrumentation-aws-lambda + py3{7,8,9}-test-instrumentation-aws-lambda ; opentelemetry-instrumentation-botocore - py3{6,7,8,9,10}-test-instrumentation-botocore + py3{7,8,9,10}-test-instrumentation-botocore pypy3-test-instrumentation-botocore + ; opentelemetry-instrumentation-boto3sqs + py3{6,7,8,9,10}-test-instrumentation-boto3sqs + pypy3-test-instrumentation-boto3sqs + ; opentelemetry-instrumentation-django ; 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 - py3{6,7}-test-instrumentation-django1 - py3{6,7,8,9}-test-instrumentation-django2 - py3{6,7,8,9,10}-test-instrumentation-django3 + py3{7}-test-instrumentation-django1 + py3{7,8,9}-test-instrumentation-django2 + py3{7,8,9,10}-test-instrumentation-django3 py3{8,9,10}-test-instrumentation-django4 pypy3-test-instrumentation-django{1,2,3} ; opentelemetry-instrumentation-dbapi - py3{6,7,8,9,10}-test-instrumentation-dbapi + py3{7,8,9,10}-test-instrumentation-dbapi pypy3-test-instrumentation-dbapi ; opentelemetry-instrumentation-boto - py3{6,7,8,9,10}-test-instrumentation-boto + py3{7,8,9,10}-test-instrumentation-boto pypy3-test-instrumentation-boto ; opentelemetry-instrumentation-elasticsearch - py3{6,7,8,9,10}-test-instrumentation-elasticsearch{2,6} + py3{7,8,9,10}-test-instrumentation-elasticsearch{2,6} pypy3-test-instrumentation-elasticsearch{2,6} ; opentelemetry-instrumentation-elasticsearch5 - py3{6,7,8,9}-test-instrumentation-elasticsearch5 + py3{7,8,9}-test-instrumentation-elasticsearch5 pypy3-test-instrumentation-elasticsearch5 ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 - py3{6,7,8,9}-test-instrumentation-falcon1 - py3{6,7,8,9,10}-test-instrumentation-falcon{2,3} + py3{7,8,9}-test-instrumentation-falcon1 + py3{7,8,9,10}-test-instrumentation-falcon{2,3} pypy3-test-instrumentation-falcon{1,2,3} ; opentelemetry-instrumentation-fastapi - ; fastapi only supports 3.6 and above. - py3{6,7,8,9,10}-test-instrumentation-fastapi + py3{7,8,9,10}-test-instrumentation-fastapi pypy3-test-instrumentation-fastapi ; opentelemetry-instrumentation-flask - py3{6,7,8,9,10}-test-instrumentation-flask + py3{7,8,9,10}-test-instrumentation-flask pypy3-test-instrumentation-flask ; opentelemetry-instrumentation-urllib - py3{6,7,8,9,10}-test-instrumentation-urllib + py3{7,8,9,10}-test-instrumentation-urllib pypy3-test-instrumentation-urllib ; opentelemetry-instrumentation-urllib3 - py3{6,7,8,9,10}-test-instrumentation-urllib3 + py3{7,8,9,10}-test-instrumentation-urllib3 pypy3-test-instrumentation-urllib3 ; opentelemetry-instrumentation-requests - py3{6,7,8,9,10}-test-instrumentation-requests + py3{7,8,9,10}-test-instrumentation-requests pypy3-test-instrumentation-requests ; opentelemetry-instrumentation-starlette. - ; starlette only supports 3.6 and above. - py3{6,7,8,9,10}-test-instrumentation-starlette + py3{7,8,9,10}-test-instrumentation-starlette pypy3-test-instrumentation-starlette ; opentelemetry-instrumentation-jinja2 - py3{6,7,8,9,10}-test-instrumentation-jinja2 + py3{7,8,9,10}-test-instrumentation-jinja2 pypy3-test-instrumentation-jinja2 ; opentelemetry-instrumentation-logging - py3{6,7,8,9,10}-test-instrumentation-logging + py3{7,8,9,10}-test-instrumentation-logging pypy3-test-instrumentation-logging ; opentelemetry-exporter-richconsole - py3{6,7,8,9,10}-test-exporter-richconsole + py3{7,8,9,10}-test-exporter-richconsole ; opentelemetry-instrumentation-mysql - py3{6,7,8,9,10}-test-instrumentation-mysql + py3{7,8,9,10}-test-instrumentation-mysql pypy3-test-instrumentation-mysql ; opentelemetry-instrumentation-psycopg2 - py3{6,7,8,9,10}-test-instrumentation-psycopg2 + py3{7,8,9,10}-test-instrumentation-psycopg2 ; ext-psycopg2 intentionally excluded from pypy3 ; opentelemetry-instrumentation-pymemcache - py3{6,7,8,9,10}-test-instrumentation-pymemcache{135,200,300,342} + py3{7,8,9,10}-test-instrumentation-pymemcache{135,200,300,342} pypy3-test-instrumentation-pymemcache{135,200,300,342} ; opentelemetry-instrumentation-pymongo - py3{6,7,8,9,10}-test-instrumentation-pymongo + py3{7,8,9,10}-test-instrumentation-pymongo pypy3-test-instrumentation-pymongo ; opentelemetry-instrumentation-pymysql - py3{6,7,8,9,10}-test-instrumentation-pymysql + py3{7,8,9,10}-test-instrumentation-pymysql pypy3-test-instrumentation-pymysql ; opentelemetry-instrumentation-pyramid - py3{6,7,8,9,10}-test-instrumentation-pyramid + py3{7,8,9,10}-test-instrumentation-pyramid pypy3-test-instrumentation-pyramid ; opentelemetry-instrumentation-asgi - py3{6,7,8,9,10}-test-instrumentation-asgi + py3{7,8,9,10}-test-instrumentation-asgi pypy3-test-instrumentation-asgi ; opentelemetry-instrumentation-asyncpg - py3{6,7,8,9,10}-test-instrumentation-asyncpg + py3{7,8,9,10}-test-instrumentation-asyncpg ; ext-asyncpg intentionally excluded from pypy3 ; opentelemetry-instrumentation-sqlite3 - py3{6,7,8,9,10}-test-instrumentation-sqlite3 + py3{7,8,9,10}-test-instrumentation-sqlite3 pypy3-test-instrumentation-sqlite3 ; opentelemetry-instrumentation-wsgi - py3{6,7,8,9,10}-test-instrumentation-wsgi + py3{7,8,9,10}-test-instrumentation-wsgi pypy3-test-instrumentation-wsgi ; opentelemetry-instrumentation-grpc - py3{6,7,8,9,10}-test-instrumentation-grpc + py3{7,8,9,10}-test-instrumentation-grpc ; opentelemetry-instrumentation-sqlalchemy - py3{6,7}-test-instrumentation-sqlalchemy{11} - py3{6,7,8,9,10}-test-instrumentation-sqlalchemy{14} + py3{7}-test-instrumentation-sqlalchemy{11} + py3{7,8,9,10}-test-instrumentation-sqlalchemy{14} pypy3-test-instrumentation-sqlalchemy{11,14} ; opentelemetry-instrumentation-redis - py3{6,7,8,9,10}-test-instrumentation-redis + py3{7,8,9,10}-test-instrumentation-redis pypy3-test-instrumentation-redis ; opentelemetry-instrumentation-remoulade @@ -159,45 +161,46 @@ envlist = ; instrumentation-remoulade intentionally excluded from pypy3 ; opentelemetry-instrumentation-celery - py3{6,7,8,9,10}-test-instrumentation-celery + py3{7,8,9,10}-test-instrumentation-celery pypy3-test-instrumentation-celery ; opentelemetry-instrumentation-sklearn - py3{6,7,8}-test-instrumentation-sklearn + py3{7,8}-test-instrumentation-sklearn ; opentelemetry-instrumentation-system-metrics py3{6,7,8,9,10}-test-instrumentation-system-metrics ; instrumentation-system-metrics intentionally excluded from pypy3 ; opentelemetry-instrumentation-tornado - py3{6,7,8,9,10}-test-instrumentation-tornado + py3{7,8,9,10}-test-instrumentation-tornado pypy3-test-instrumentation-tornado ; opentelemetry-instrumentation-httpx - py3{6,7,8,9,10}-test-instrumentation-httpx{18,21} + py3{7,8,9,10}-test-instrumentation-httpx{18,21} pypy3-test-instrumentation-httpx{18,21} ; opentelemetry-util-http - py3{6,7,8,9,10}-test-util-http + py3{7,8,9,10}-test-util-http pypy3-test-util-http ; opentelemetry-propagator-aws-xray - py3{6,7,8,9,10}-test-propagator-aws-xray + py3{7,8,9,10}-test-propagator-aws-xray pypy3-test-propagator-aws-xray ; opentelemetry-propagator-ot-trace - py3{6,7,8,9,10}-test-propagator-ot-trace + py3{7,8,9,10}-test-propagator-ot-trace pypy3-test-propagator-ot-trace ; opentelemetry-instrumentation-pika - py3{6,7,8,9,10}-test-instrumentation-pika{0,1} + py3{7,8,9,10}-test-instrumentation-pika{0,1} pypy3-test-instrumentation-pika{0,1} ; opentelemetry-instrumentation-kafka-python - py3{6,7,8,9,10}-test-instrumentation-kafka-python + py3{7,8,9,10}-test-instrumentation-kafka-python pypy3-test-instrumentation-kafka-python lint + spellcheck docker-tests docs @@ -259,6 +262,7 @@ changedir = 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-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 @@ -298,7 +302,7 @@ changedir = commands_pre = ; Install without -e to test the actual installation - py3{6,7,8,9,10}: python -m pip install -U pip setuptools wheel + py3{7,8,9,10}: 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" @@ -328,6 +332,8 @@ commands_pre = boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] boto: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] + boto3sqs: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] + falcon{1,2,3}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] flask: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] @@ -421,6 +427,15 @@ changedir = docs commands = sphinx-build -E -a -W -b html -T . _build/html +[testenv:spellcheck] +basepython: python3.9 +recreate = True +deps = + codespell + +commands = + codespell + [testenv:lint] basepython: python3.9 recreate = False @@ -445,6 +460,7 @@ commands_pre = 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] diff --git a/util/opentelemetry-util-http/setup.cfg b/util/opentelemetry-util-http/setup.cfg index 8abce2cb06..6e8c046c9f 100644 --- a/util/opentelemetry-util-http/setup.cfg +++ b/util/opentelemetry-util-http/setup.cfg @@ -28,17 +28,16 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 [options] -python_requires = >=3.6 +python_requires = >=3.7 package_dir= =src packages=find_namespace: [options.packages.find] -where = src \ No newline at end of file +where = src 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 aa34fb439a..9088da3a37 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -18,6 +18,8 @@ from typing import Iterable, List from urllib.parse import urlparse, urlunparse +from opentelemetry.semconv.trace import SpanAttributes + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST = ( "OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST" ) @@ -25,6 +27,26 @@ "OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE" ) +# List of recommended metrics 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 ExcludeList: """Class to exclude certain paths (given as a list of regexes) from tracing requests""" @@ -102,7 +124,7 @@ def remove_url_credentials(url: str) -> str: parsed_url.fragment, ) ) - except ValueError: # an unparseable url was passed + except ValueError: # an unparsable url was passed pass return url @@ -125,3 +147,19 @@ def get_custom_headers(env_var: str) -> List[str]: for custom_headers in custom_headers.split(",") ] return custom_headers + + +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_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 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 268a795344..6b2801561b 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.32b0" +__version__ = "0.33b0" diff --git a/util/opentelemetry-util-http/tests/test_capture_custom_headers.py b/util/opentelemetry-util-http/tests/test_capture_custom_headers.py index eb1a4f6a7e..e6e1583ffb 100644 --- a/util/opentelemetry-util-http/tests/test_capture_custom_headers.py +++ b/util/opentelemetry-util-http/tests/test_capture_custom_headers.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import unittest from unittest.mock import patch -from opentelemetry.test.test_base import TestBase from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, @@ -24,7 +24,7 @@ ) -class TestCaptureCustomHeaders(TestBase): +class TestCaptureCustomHeaders(unittest.TestCase): @patch.dict( "os.environ", { diff --git a/util/opentelemetry-util-http/tests/test_http_excluded_urls.py b/util/opentelemetry-util-http/tests/test_http_excluded_urls.py index af524d2e7b..3fea381050 100644 --- a/util/opentelemetry-util-http/tests/test_http_excluded_urls.py +++ b/util/opentelemetry-util-http/tests/test_http_excluded_urls.py @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import unittest from unittest.mock import patch -from opentelemetry.test.test_base import TestBase from opentelemetry.util.http import get_excluded_urls -class TestGetExcludedUrls(TestBase): +class TestGetExcludedUrls(unittest.TestCase): @patch.dict( "os.environ", {