From e84bfff6cf8e57169aa18560a90e4d1d52c3f8d4 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 15 Apr 2024 18:26:57 +0200 Subject: [PATCH 01/28] readthedocs: update build os config (#2389) --- .readthedocs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 3dcf0e5cf6..2a3c920b45 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,9 +6,10 @@ sphinx: configuration: docs/conf.py build: - image: latest + os: "ubuntu-22.04" + tools: + python: "3.8" python: - version: 3.8 install: - requirements: docs-requirements.txt From 8322ee790e25b9103f4b527244959cad20d7817c Mon Sep 17 00:00:00 2001 From: John Bley Date: Tue, 16 Apr 2024 12:36:37 -0400 Subject: [PATCH 02/28] Fix all issues from shellcheck --severity=warning (#2354) --- .github/workflows/shellcheck.yml | 19 +++++++++++++++++++ .../proto/generate-proto-py.sh | 1 - scripts/build.sh | 4 ++-- scripts/build_a_package.sh | 8 ++++---- scripts/coverage.sh | 3 --- 5 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/shellcheck.yml diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 0000000000..68d12b805f --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,19 @@ +name: Shellcheck + +on: + push: + branches-ignore: + - 'release/*' + pull_request: + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install shellcheck + run: sudo apt update && sudo apt install --assume-yes shellcheck + + - name: Run shellcheck + run: find . -name \*.sh | xargs shellcheck --severity=warning diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh b/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh index 5f6129df55..a07181add3 100755 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/proto/generate-proto-py.sh @@ -6,7 +6,6 @@ PROTO_VERSION=v1.3.2 # SRC_DIR is from protoc perspective. ie its the destination for our checkouts/clones SRC_DIR=opentelemetry/exporter/prometheus_remote_write/gen/ -DST_DIR=../src/opentelemetry/exporter/prometheus_remote_write/gen/ #TODO: # Check that black & protoc are installed properly diff --git a/scripts/build.sh b/scripts/build.sh index fa490a6a35..247bb24b4e 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -8,13 +8,13 @@ set -ev # Get the latest versions of packaging tools python3 -m pip install --upgrade pip build setuptools wheel -BASEDIR=$(dirname $(readlink -f $(dirname $0))) +BASEDIR=$(dirname "$(readlink -f "$(dirname $0)")") DISTDIR=dist ( cd $BASEDIR mkdir -p $DISTDIR - rm -rf $DISTDIR/* + rm -rf ${DISTDIR:?}/* for d in exporter/*/ opentelemetry-instrumentation/ opentelemetry-contrib-instrumentations/ opentelemetry-distro/ instrumentation/*/ propagator/*/ resource/*/ sdk-extension/*/ util/*/ ; do ( diff --git a/scripts/build_a_package.sh b/scripts/build_a_package.sh index f3baa8a65a..333deccd80 100755 --- a/scripts/build_a_package.sh +++ b/scripts/build_a_package.sh @@ -22,7 +22,7 @@ set -ev if [ -z $GITHUB_REF ]; then echo 'Failed to run script, missing workflow env variable GITHUB_REF.' - exit -1 + exit 1 fi pkg_name_and_version=${GITHUB_REF#refs/tags/*} @@ -40,13 +40,13 @@ cd $basedir distdir=${basedir}/dist mkdir -p $distdir -rm -rf $distdir/* +rm -rf ${distdir:?}/* pyproject_toml_file_path=$(ls **/$pkg_name/pyproject.toml) if [ -z $pyproject_toml_file_path ]; then echo "Error! pyproject.toml not found for $pkg_name, can't build." - exit -1 + exit 1 fi directory_with_package=$(dirname $pyproject_toml_file_path) @@ -61,7 +61,7 @@ pkg_tar_gz_file=${pkg_name}-${pkg_version}.tar.gz if ! [ -f $pkg_tar_gz_file ]; then echo 'Error! Tag version does not match version built using latest package files.' - exit -1 + exit 1 fi # Build a wheel for the source distribution diff --git a/scripts/coverage.sh b/scripts/coverage.sh index 4015c6884a..02ce1eed55 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -11,9 +11,6 @@ function cov { ${1} } -PYTHON_VERSION=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))') -PYTHON_VERSION_INFO=(${PYTHON_VERSION//./ }) - coverage erase cov instrumentation/opentelemetry-instrumentation-flask From 99678ccd3a6ab5afe2661d00a27a6cdf3391c145 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Tue, 16 Apr 2024 14:04:17 -0700 Subject: [PATCH 03/28] Add section for semantic convention status for instrumentations (#2433) --- README.md | 6 +- instrumentation/README.md | 100 +++++++++--------- .../instrumentation/requests/package.py | 2 + scripts/generate_instrumentation_readme.py | 10 +- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 6968de717e..133acf81f6 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,15 @@ To release a package as `1.0` stable, the package: - e.g. If an instrumentation package uses flags, a token as context, or parameters that are not typical of the `BaseInstrumentor` class, these are documented - After the release of `1.0`, a CODEOWNER may no longer feel like they have the bandwidth to meet the responsibilities of maintaining the package. That's not a problem at all, life happens! However, if that is the case, we ask that the CODEOWNER please raise an issue indicating that they would like to be removed as a CODEOWNER so that they don't get pinged on future PRs. Ultimately, we hope to use that issue to find a new CODEOWNER. +## Semantic Convention status of instrumentations + +In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the [semantic convention migration plan](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/migration-guide.md) for several instrumentations. Currently this plan is only being adopted for HTTP-related instrumentations, but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `experimental`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan. + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) -We meet weekly on Thursday, and the time of the meeting alternates between 9AM PT and 4PM PT. The meeting is subject to change depending on contributors' availability. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com) for specific dates and for the Zoom link. +We meet weekly on Thursday at 9AM PT. The meeting is subject to change depending on contributors' availability. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=c_2bf73e3b6b530da4babd444e72b76a6ad893a5c3f43cf40467abc7a9a897f977%40group.calendar.google.com) for specific dates and for the Zoom link. Meeting notes are available as a public [Google doc](https://docs.google.com/document/d/1CIMGoIOZ-c3-igzbd6_Pnxx1SjAkjwqoYSUWxPY8XIs/edit). For edit access, get in touch on [GitHub Discussions](https://github.com/open-telemetry/opentelemetry-python/discussions). diff --git a/instrumentation/README.md b/instrumentation/README.md index 62caabd81a..284037d707 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -1,51 +1,51 @@ -| Instrumentation | Supported Packages | Metrics support | -| --------------- | ------------------ | --------------- | -| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No -| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No -| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No -| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No -| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No -| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No -| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No -| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No -| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No -| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No -| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No -| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No -| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No -| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.3.0 | No -| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No -| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes -| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No -| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | Yes -| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes -| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes -| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No -| [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No -| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No -| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0 | No -| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No -| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python ~= 8.0 | No -| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No -| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No -| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No -| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No -| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No -| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No -| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No -| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes -| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No -| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No -| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes -| [opentelemetry-instrumentation-sklearn](./opentelemetry-instrumentation-sklearn) | scikit-learn ~= 0.24.0 | No -| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy | Yes -| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No -| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette ~= 0.13.0 | Yes -| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No -| [opentelemetry-instrumentation-threading](./opentelemetry-instrumentation-threading) | threading | No -| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes -| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No -| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes -| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes -| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes \ No newline at end of file +| Instrumentation | Supported Packages | Metrics support | Semconv status | +| --------------- | ------------------ | --------------- | -------------- | +| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No | experimental +| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No | experimental +| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No | experimental +| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No | experimental +| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No | experimental +| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No | experimental +| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No | experimental +| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No | experimental +| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No | experimental +| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No | experimental +| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No | experimental +| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.3.0 | No | experimental +| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | experimental +| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | experimental +| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No | experimental +| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | Yes | experimental +| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | experimental +| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | experimental +| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No | experimental +| [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No | experimental +| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No | experimental +| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0 | No | experimental +| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No | experimental +| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python ~= 8.0 | No | experimental +| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No | experimental +| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No | experimental +| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No | experimental +| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No | experimental +| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No | experimental +| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No | experimental +| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No | experimental +| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes | experimental +| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No | experimental +| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No | experimental +| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes | migration +| [opentelemetry-instrumentation-sklearn](./opentelemetry-instrumentation-sklearn) | scikit-learn ~= 0.24.0 | No | experimental +| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy | Yes | experimental +| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No | experimental +| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette ~= 0.13.0 | Yes | experimental +| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | experimental +| [opentelemetry-instrumentation-threading](./opentelemetry-instrumentation-threading) | threading | No | experimental +| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes | experimental +| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No | experimental +| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes | experimental +| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes | experimental +| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes | experimental \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py index 8424bfeb2a..9cd93a9150 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/package.py @@ -16,3 +16,5 @@ _instruments = ("requests ~= 2.0",) _supports_metrics = True + +_semconv_status = "migration" diff --git a/scripts/generate_instrumentation_readme.py b/scripts/generate_instrumentation_readme.py index 00045cd73c..79b8a5533d 100755 --- a/scripts/generate_instrumentation_readme.py +++ b/scripts/generate_instrumentation_readme.py @@ -23,8 +23,8 @@ _prefix = "opentelemetry-instrumentation-" header = """ -| Instrumentation | Supported Packages | Metrics support | -| --------------- | ------------------ | --------------- |""" +| Instrumentation | Supported Packages | Metrics support | Semconv status | +| --------------- | ------------------ | --------------- | -------------- |""" def main(): @@ -63,13 +63,17 @@ def main(): instruments = pkg_info["_instruments"] supports_metrics = pkg_info.get("_supports_metrics") + semconv_status = pkg_info.get("_semconv_status") if not instruments: instruments = (name,) + if not semconv_status: + semconv_status = "experimental" + metric_column = "Yes" if supports_metrics else "No" table.append( - f"| [{instrumentation}](./{instrumentation}) | {','.join(instruments)} | {metric_column}" + f"| [{instrumentation}](./{instrumentation}) | {','.join(instruments)} | {metric_column} | {semconv_status}" ) with open( From 07318bd3782e8db237ab9ead66b4c1e694c90a5e Mon Sep 17 00:00:00 2001 From: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Date: Wed, 17 Apr 2024 09:09:55 -0700 Subject: [PATCH 04/28] Change AwsLambdaInstrumentor span attrs to meet faas semconv (#2372) --- CHANGELOG.md | 2 ++ .../opentelemetry/instrumentation/aws_lambda/__init__.py | 8 ++++---- .../tests/test_aws_lambda_instrumentation_manual.py | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 911ae8fa70..89495abe73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rename `type` attribute to `asgi.event.type` in `opentelemetry-instrumentation-asgi` ([#2300](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2300)) +- Rename AwsLambdaInstrumentor span attributes `faas.id` to `cloud.resource_id`, `faas.execution` to `faas.invocation_id` + ([#2372](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2372)) ### Added 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 3ec22d4c0e..8f29a0ec38 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -340,17 +340,17 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches if span.is_recording(): lambda_context = args[1] # NOTE: The specs mention an exception here, allowing the - # `ResourceAttributes.FAAS_ID` attribute to be set as a span + # `SpanAttributes.CLOUD_RESOURCE_ID` attribute to be set as a span # attribute instead of a resource attribute. # # See more: - # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/faas.md#example + # https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#resource-detector span.set_attribute( - ResourceAttributes.FAAS_ID, + SpanAttributes.CLOUD_RESOURCE_ID, lambda_context.invoked_function_arn, ) span.set_attribute( - SpanAttributes.FAAS_EXECUTION, + SpanAttributes.FAAS_INVOCATION_ID, lambda_context.aws_request_id, ) diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py index 9bf6f47d7b..51ebb67ebc 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py @@ -145,8 +145,8 @@ def test_active_tracing(self): self.assertSpanHasAttributes( span, { - ResourceAttributes.FAAS_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn, - SpanAttributes.FAAS_EXECUTION: MOCK_LAMBDA_CONTEXT.aws_request_id, + SpanAttributes.CLOUD_RESOURCE_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn, + SpanAttributes.FAAS_INVOCATION_ID: MOCK_LAMBDA_CONTEXT.aws_request_id, ResourceAttributes.CLOUD_ACCOUNT_ID: MOCK_LAMBDA_CONTEXT.invoked_function_arn.split( ":" )[ From 82b07959a91bf23a470afcec8710bab956aba2a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADdio=20Neto?= <9735060+emdneto@users.noreply.github.com> Date: Wed, 17 Apr 2024 13:48:09 -0300 Subject: [PATCH 05/28] fix: instrumentation-celery test tasks CustomError (#2416) * fix: instrumentation-celery test tasks CustomError * chore: lint --------- Co-authored-by: Diego Hurtado --- .../opentelemetry-instrumentation-celery/tests/test_tasks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py b/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py index ed4dbb5b1d..3ac6a5a70c 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py +++ b/instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py @@ -125,8 +125,9 @@ def test_task_raises(self): self.assertIn(SpanAttributes.EXCEPTION_STACKTRACE, event.attributes) - self.assertEqual( - event.attributes[SpanAttributes.EXCEPTION_TYPE], "CustomError" + # TODO: use plain assertEqual after 1.25 is released (https://github.com/open-telemetry/opentelemetry-python/pull/3837) + self.assertIn( + "CustomError", event.attributes[SpanAttributes.EXCEPTION_TYPE] ) self.assertEqual( From ab50a4e1514073cb8c299973067c14f4393f899c Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 17 Apr 2024 19:08:18 +0200 Subject: [PATCH 06/28] tox: stop testing on python < 3.8 (#2414) --- tox.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index 420ae899f0..3583b7319f 100644 --- a/tox.ini +++ b/tox.ini @@ -27,7 +27,7 @@ envlist = pypy3-test-instrumentation-aiohttp-client ; opentelemetry-instrumentation-aiohttp-server - py3{6,8,9,10,11}-test-instrumentation-aiohttp-server + py3{8,9,10,11}-test-instrumentation-aiohttp-server pypy3-test-instrumentation-aiohttp-server ; opentelemetry-instrumentation-aiopg @@ -44,7 +44,7 @@ envlist = ; pypy3-test-instrumentation-botocore ; opentelemetry-instrumentation-boto3sqs - py3{6,8,9,10,11}-test-instrumentation-boto3sqs + py3{8,9,10,11}-test-instrumentation-boto3sqs ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-boto3sqs @@ -144,7 +144,7 @@ envlist = pypy3-test-exporter-richconsole ; opentelemetry-exporter-prometheus-remote-write - py3{6,8,9,10,11}-test-exporter-prometheus-remote-write + py3{8,9,10,11}-test-exporter-prometheus-remote-write pypy3-test-exporter-prometheus-remote-write ; opentelemetry-instrumentation-mysql @@ -160,7 +160,7 @@ envlist = ; ext-psycopg2 intentionally excluded from pypy3 ; opentelemetry-instrumentation-psycopg - py3{7,8,9,10,11}-test-instrumentation-psycopg + py3{8,9,10,11}-test-instrumentation-psycopg pypy3-test-instrumentation-psycopg ; opentelemetry-instrumentation-pymemcache @@ -230,7 +230,7 @@ envlist = py3{8}-test-instrumentation-sklearn ; opentelemetry-instrumentation-system-metrics - py3{6,8,9,10,11}-test-instrumentation-system-metrics + py3{8,9,10,11}-test-instrumentation-system-metrics pypy3-test-instrumentation-system-metrics ; opentelemetry-instrumentation-threading From 9ce1c26d2732dfbdadbb492fc38c562dcd08ed2e Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 17 Apr 2024 20:19:34 +0200 Subject: [PATCH 07/28] django: Bump django version to latest (#2427) --- .../test-requirements-1.txt | 2 +- .../test-requirements-2.txt | 2 +- .../test-requirements-3.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt index 116dc015ec..548db1b8e3 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt @@ -1,7 +1,7 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -Django==3.2.24 +Django==3.2.25 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt index ac3b40e16b..0970d2f253 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt @@ -2,7 +2,7 @@ asgiref==3.7.2 attrs==23.2.0 backports.zoneinfo==0.2.1 Deprecated==1.2.14 -Django==4.2.10 +Django==4.2.11 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 diff --git a/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt index 3bb32c4c6b..d853c05877 100644 --- a/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt +++ b/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt @@ -1,7 +1,7 @@ asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 -Django==4.2.10 +Django==4.2.11 importlib-metadata==6.11.0 iniconfig==2.0.0 packaging==23.2 From 4de0e5659d451baee65af412242b95f174444d87 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Thu, 18 Apr 2024 15:57:26 +0200 Subject: [PATCH 08/28] elasticsearch: stop testing on ancient versions (#2422) Pick 6.0 as the baseline. --- CHANGELOG.md | 2 ++ docs-requirements.txt | 2 +- .../pyproject.toml | 2 +- .../test-requirements-0.txt | 22 ------------- .../test-requirements-1.txt | 22 ------------- ...irements-2.txt => test-requirements-6.txt} | 0 .../tests/helpers_es2.py | 33 ------------------- .../tests/helpers_es5.py | 33 ------------------- .../tests/test_elasticsearch.py | 4 --- .../instrumentation/bootstrap_gen.py | 2 +- tox.ini | 16 +++------ 11 files changed, 10 insertions(+), 128 deletions(-) delete mode 100644 instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt delete mode 100644 instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt rename instrumentation/opentelemetry-instrumentation-elasticsearch/{test-requirements-2.txt => test-requirements-6.txt} (100%) delete mode 100644 instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py delete mode 100644 instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 89495abe73..fb92d56507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2300](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2300)) - Rename AwsLambdaInstrumentor span attributes `faas.id` to `cloud.resource_id`, `faas.execution` to `faas.invocation_id` ([#2372](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2372)) +- Drop support for instrumenting elasticsearch client < 6` + ([#2422](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2422)) ### Added diff --git a/docs-requirements.txt b/docs-requirements.txt index aff449fcf8..72f4472902 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -28,7 +28,7 @@ boto3~=1.0 cassandra-driver~=3.25 celery>=4.0 confluent-kafka>= 1.8.2,<= 2.3.0 -elasticsearch>=2.0,<9.0 +elasticsearch>=6.0,<9.0 flask~=2.0 falcon~=2.0 grpcio~=1.27 diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml b/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml index 659366181a..f5ba221b7f 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ [project.optional-dependencies] instruments = [ - "elasticsearch >= 2.0", + "elasticsearch >= 6.0", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt deleted file mode 100644 index 216d1c0b02..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt +++ /dev/null @@ -1,22 +0,0 @@ -asgiref==3.7.2 -attrs==23.2.0 -Deprecated==1.2.14 -elasticsearch==2.4.1 -elasticsearch-dsl==2.2.0 -importlib-metadata==6.11.0 -iniconfig==2.0.0 -packaging==23.2 -pluggy==1.4.0 -py==1.11.0 -py-cpuinfo==9.0.0 -pytest==7.1.3 -pytest-benchmark==4.0.0 -python-dateutil==2.8.2 -six==1.16.0 -tomli==2.0.1 -typing_extensions==4.10.0 -urllib3==1.26.18 -wrapt==1.16.0 -zipp==3.17.0 --e opentelemetry-instrumentation --e instrumentation/opentelemetry-instrumentation-elasticsearch diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt deleted file mode 100644 index 2c51c87508..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt +++ /dev/null @@ -1,22 +0,0 @@ -asgiref==3.7.2 -attrs==23.2.0 -Deprecated==1.2.14 -elasticsearch==5.5.3 -elasticsearch-dsl==5.4.0 -importlib-metadata==6.11.0 -iniconfig==2.0.0 -packaging==23.2 -pluggy==1.4.0 -py==1.11.0 -py-cpuinfo==9.0.0 -pytest==7.1.3 -pytest-benchmark==4.0.0 -python-dateutil==2.8.2 -six==1.16.0 -tomli==2.0.1 -typing_extensions==4.10.0 -urllib3==2.2.1 -wrapt==1.16.0 -zipp==3.17.0 --e opentelemetry-instrumentation --e instrumentation/opentelemetry-instrumentation-elasticsearch diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt similarity index 100% rename from instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt rename to instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py deleted file mode 100644 index 008a95d671..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es2.py +++ /dev/null @@ -1,33 +0,0 @@ -from elasticsearch_dsl import ( # pylint: disable=no-name-in-module - DocType, - String, -) - - -class Article(DocType): - title = String(analyzer="snowball", fields={"raw": String()}) - body = String(analyzer="snowball") - - class Meta: - index = "test-index" - - -dsl_create_statement = { - "mappings": { - "article": { - "properties": { - "title": { - "analyzer": "snowball", - "fields": {"raw": {"type": "string"}}, - "type": "string", - }, - "body": {"analyzer": "snowball", "type": "string"}, - } - } - }, - "settings": {"analysis": {}}, -} -dsl_index_result = (1, {}, '{"created": true}') -dsl_index_span_name = "Elasticsearch/test-index/article/2" -dsl_index_url = "/test-index/article/2" -dsl_search_method = "GET" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py deleted file mode 100644 index cf32d98863..0000000000 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es5.py +++ /dev/null @@ -1,33 +0,0 @@ -from elasticsearch_dsl import ( # pylint: disable=no-name-in-module - DocType, - Keyword, - Text, -) - - -class Article(DocType): - title = Text(analyzer="snowball", fields={"raw": Keyword()}) - body = Text(analyzer="snowball") - - class Meta: - index = "test-index" - - -dsl_create_statement = { - "mappings": { - "article": { - "properties": { - "title": { - "analyzer": "snowball", - "fields": {"raw": {"type": "keyword"}}, - "type": "text", - }, - "body": {"analyzer": "snowball", "type": "text"}, - } - } - }, -} -dsl_index_result = (1, {}, '{"created": true}') -dsl_index_span_name = "Elasticsearch/test-index/article/2" -dsl_index_url = "/test-index/article/2" -dsl_search_method = "GET" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py index 6008108d79..5d1c85f77d 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py @@ -44,10 +44,6 @@ from . import helpers_es7 as helpers # pylint: disable=no-name-in-module elif major_version == 6: from . import helpers_es6 as helpers # pylint: disable=no-name-in-module -elif major_version == 5: - from . import helpers_es5 as helpers # pylint: disable=no-name-in-module -else: - from . import helpers_es2 as helpers # pylint: disable=no-name-in-module Article = helpers.Article diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 455d08e41a..9eebd5bb38 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -73,7 +73,7 @@ "instrumentation": "opentelemetry-instrumentation-django==0.46b0.dev", }, { - "library": "elasticsearch >= 2.0", + "library": "elasticsearch >= 6.0", "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.46b0.dev", }, { diff --git a/tox.ini b/tox.ini index 3583b7319f..bee544cb70 100644 --- a/tox.ini +++ b/tox.ini @@ -78,13 +78,9 @@ envlist = ; FIXME: Elasticsearch >=7 causes CI workflow tests to hang, see open-telemetry/opentelemetry-python-contrib#620 ; The numbers at the end of the environment names ; below mean these dependencies are being used: - ; 0: elasticsearch-dsl>=2.0,<3.0 elasticsearch>=2.0,<3.0 - ; 1: elasticsearch-dsl>=5.0,<6.0 elasticsearch>=5.0,<6.0 - ; 2: elasticsearch-dsl>=6.0,<7.0 elasticsearch>=6.0,<7.0 - py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,2} - pypy3-test-instrumentation-elasticsearch-{0,2} - py3{8,9}-test-instrumentation-elasticsearch-1 - pypy3-test-instrumentation-elasticsearch-1 + ; 6: elasticsearch-dsl>=6.0,<7.0 elasticsearch>=6.0,<7.0 + py3{8,9,10,11}-test-instrumentation-elasticsearch-6 + pypy3-test-instrumentation-elasticsearch-6 ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 @@ -452,9 +448,7 @@ commands_pre = sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt - elasticsearch-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt - elasticsearch-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt - elasticsearch-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt + elasticsearch-6: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt asyncio: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt @@ -617,7 +611,7 @@ commands_pre = # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install # for your OS to install the required dependencies pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-2.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt From 7656bdb8fe46a159158f98cc6de2b6ef07ad793a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9ni?= Date: Thu, 18 Apr 2024 20:33:42 +0200 Subject: [PATCH 09/28] fix(grpc): aio grpc client interceptor incorrect metadata handling (#2363) --- CHANGELOG.md | 5 +++++ .../instrumentation/grpc/_aio_client.py | 12 +++++------- .../tests/_aio_client.py | 8 +++++--- .../tests/_client.py | 16 +++++++++++----- .../tests/test_aio_client_interceptor.py | 9 ++++----- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb92d56507..146b15a5f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-threading` Initial release for threading ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) +### Fixed + +- `opentelemetry-instrumentation-grpc` AioClientInterceptor should propagate with a Metadata object + ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) + ## Version 1.24.0/0.45b0 (2024-03-28) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py index 8fc992be73..9c8cc5cdf3 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_aio_client.py @@ -14,10 +14,9 @@ import functools import logging -from collections import OrderedDict import grpc -from grpc.aio import ClientCallDetails +from grpc.aio import ClientCallDetails, Metadata from opentelemetry.instrumentation.grpc._client import ( OpenTelemetryClientInterceptor, @@ -55,20 +54,19 @@ def callback(call): class _BaseAioClientInterceptor(OpenTelemetryClientInterceptor): @staticmethod - def propagate_trace_in_details(client_call_details): + def propagate_trace_in_details(client_call_details: ClientCallDetails): metadata = client_call_details.metadata if not metadata: - mutable_metadata = OrderedDict() + mutable_metadata = Metadata() else: - mutable_metadata = OrderedDict(metadata) + mutable_metadata = Metadata(*tuple(metadata)) inject(mutable_metadata, setter=_carrier_setter) - metadata = tuple(mutable_metadata.items()) return ClientCallDetails( client_call_details.method, client_call_details.timeout, - metadata, + mutable_metadata, client_call_details.credentials, client_call_details.wait_for_ready, ) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py index 9658df1587..6c0b8eac21 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/_aio_client.py @@ -21,7 +21,7 @@ async def simple_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - return await stub.SimpleMethod(request) + return await stub.SimpleMethod(request, metadata=(("key", "value"),)) async def client_streaming_method(stub, error=False): @@ -41,7 +41,7 @@ def server_streaming_method(stub, error=False): client_id=CLIENT_ID, request_data="error" if error else "data" ) - return stub.ServerStreamingMethod(request) + return stub.ServerStreamingMethod(request, metadata=(("key", "value"),)) def bidirectional_streaming_method(stub, error=False): @@ -53,4 +53,6 @@ def request_messages(): ) yield request - return stub.BidirectionalStreamingMethod(request_messages()) + return stub.BidirectionalStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py index 69222b37a4..67e7d0a625 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/_client.py @@ -21,14 +21,14 @@ def simple_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - stub.SimpleMethod(request) + stub.SimpleMethod(request, metadata=(("key", "value"),)) def simple_method_future(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - return stub.SimpleMethod.future(request) + return stub.SimpleMethod.future(request, metadata=(("key", "value"),)) def client_streaming_method(stub, error=False): @@ -40,14 +40,18 @@ def request_messages(): ) yield request - stub.ClientStreamingMethod(request_messages()) + stub.ClientStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) def server_streaming_method(stub, error=False): request = Request( client_id=CLIENT_ID, request_data="error" if error else "data" ) - response_iterator = stub.ServerStreamingMethod(request) + response_iterator = stub.ServerStreamingMethod( + request, metadata=(("key", "value"),) + ) list(response_iterator) @@ -59,6 +63,8 @@ def request_messages(): ) yield request - response_iterator = stub.BidirectionalStreamingMethod(request_messages()) + response_iterator = stub.BidirectionalStreamingMethod( + request_messages(), metadata=(("key", "value"),) + ) list(response_iterator) diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py index 6b1006b8a3..21dbc44066 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_aio_client_interceptor.py @@ -305,11 +305,10 @@ async def test_client_interceptor_trace_context_propagation(self): await simple_method(stub) metadata = recording_interceptor.recorded_details.metadata - assert len(metadata) == 2 - assert metadata[0][0] == "mock-traceid" - assert metadata[0][1] == "0" - assert metadata[1][0] == "mock-spanid" - assert metadata[1][1] == "0" + assert len(metadata) == 3 + assert metadata.get_all("key") == ["value"] + assert metadata.get_all("mock-traceid") == ["0"] + assert metadata.get_all("mock-spanid") == ["0"] finally: set_global_textmap(previous_propagator) From 2317adcc3478fe0d886d22b05e51d71e4daabfbd Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 19 Apr 2024 10:59:05 -0700 Subject: [PATCH 10/28] HTTP transition for wsgi (#2425) --- CHANGELOG.md | 17 +- .../tests/test_falcon.py | 29 +- .../tests/test_programmatic.py | 28 +- .../tests/test_automatic.py | 13 +- .../tests/test_programmatic.py | 1 + .../instrumentation/requests/__init__.py | 43 ++- .../tests/test_requests_integration.py | 7 +- .../instrumentation/wsgi/__init__.py | 284 +++++++++----- .../tests/test_wsgi_middleware.py | 354 ++++++++++++++++-- .../opentelemetry/instrumentation/_semconv.py | 313 ++++++++++++---- .../src/opentelemetry/util/http/__init__.py | 9 +- 11 files changed, 852 insertions(+), 246 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 146b15a5f0..6db0e04e68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,6 @@ 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 -- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the - `opentelemetry_resource_detector` entry point - ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) ### Breaking changes @@ -21,6 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the + `opentelemetry_resource_detector` entry point + ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) +- `opentelemetry-instrumentation-wsgi` Implement new semantic convention opt-in with stable http semantic conventions + ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) - `opentelemetry-instrumentation-threading` Initial release for threading ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) @@ -29,6 +31,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-grpc` AioClientInterceptor should propagate with a Metadata object ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) +### Added + +- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the `opentelemetry_resource_detector` entry point + ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) +- `opentelemetry-instrumentation-wsgi` Implement new semantic convention opt-in with stable http semantic conventions + ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) +- `opentelemetry-instrumentation-threading` Initial release for threading + ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) + ## Version 1.24.0/0.45b0 (2024-03-28) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 2245dbfd80..bf7f1d4f49 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -16,21 +16,21 @@ from unittest.mock import Mock, patch import pytest -from falcon import __version__ as _falcon_verison +from falcon import __version__ as _falcon_version from falcon import testing from packaging import version as package_version from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.falcon import FalconInstrumentor from opentelemetry.instrumentation.propagators import ( TraceResponsePropagator, get_global_response_propagator, set_global_response_propagator, ) -from opentelemetry.instrumentation.wsgi import ( - _active_requests_count_attrs, - _duration_attrs, -) from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -53,8 +53,8 @@ "http.server.duration", ] _recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, } @@ -125,7 +125,7 @@ def _test_method(self, method): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", "falcon.resource": "HelloWorldResource", SpanAttributes.HTTP_STATUS_CODE: 201, @@ -156,7 +156,7 @@ def test_404(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", SpanAttributes.HTTP_STATUS_CODE: 404, }, @@ -193,7 +193,7 @@ def test_500(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", SpanAttributes.HTTP_STATUS_CODE: 500, }, @@ -226,7 +226,7 @@ def test_url_template(self): SpanAttributes.NET_HOST_PORT: 80, SpanAttributes.HTTP_HOST: "falconframework.org", SpanAttributes.HTTP_TARGET: "/", - SpanAttributes.NET_PEER_PORT: "65133", + SpanAttributes.NET_PEER_PORT: 65133, SpanAttributes.HTTP_FLAVOR: "1.1", "falcon.resource": "UserResource", SpanAttributes.HTTP_STATUS_CODE: 200, @@ -336,6 +336,7 @@ def test_falcon_metric_values(self): "http.flavor": "1.1", "http.server_name": "falconframework.org", "net.host.port": 80, + "net.host.name": "falconframework.org", "http.status_code": 404, } expected_requests_count_attributes = { @@ -344,6 +345,8 @@ def test_falcon_metric_values(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "falconframework.org", + "net.host.name": "falconframework.org", + "net.host.port": 80, } start = default_timer() self.client().simulate_get("/hello/756") @@ -523,7 +526,7 @@ def test_custom_request_header_not_added_in_internal_span(self): self.assertNotIn(key, span.attributes) @pytest.mark.skipif( - condition=package_version.parse(_falcon_verison) + condition=package_version.parse(_falcon_version) < package_version.parse("2.0.0"), reason="falcon<2 does not implement custom response headers", ) @@ -558,7 +561,7 @@ def test_custom_response_header_added_in_server_span(self): self.assertNotIn(key, span.attributes) @pytest.mark.skipif( - condition=package_version.parse(_falcon_verison) + condition=package_version.parse(_falcon_version) < package_version.parse("2.0.0"), reason="falcon<2 does not implement custom response headers", ) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index dec265907f..82ca88460c 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -18,17 +18,17 @@ from flask import Flask, request from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.instrumentation.propagators import ( TraceResponsePropagator, get_global_response_propagator, set_global_response_propagator, ) -from opentelemetry.instrumentation.wsgi import ( - OpenTelemetryMiddleware, - _active_requests_count_attrs, - _duration_attrs, -) +from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -54,6 +54,7 @@ def expected_attributes(override_attributes): SpanAttributes.HTTP_SERVER_NAME: "localhost", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, + SpanAttributes.NET_HOST_NAME: "localhost", SpanAttributes.HTTP_HOST: "localhost", SpanAttributes.HTTP_TARGET: "/", SpanAttributes.HTTP_FLAVOR: "1.1", @@ -69,8 +70,8 @@ def expected_attributes(override_attributes): "http.server.duration", ] _recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, } @@ -358,6 +359,7 @@ def test_basic_metric_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 200, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "GET", @@ -365,6 +367,8 @@ def test_basic_metric_success(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, } self._assert_basic_metric( expected_duration_attributes, @@ -374,20 +378,23 @@ def test_basic_metric_success(self): def test_basic_metric_nonstandard_http_method_success(self): self.client.open("/hello/756", method="NONSTANDARD") expected_duration_attributes = { - "http.method": "UNKNOWN", + "http.method": "_OTHER", "http.host": "localhost", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 405, + "net.host.name": "localhost", } expected_requests_count_attributes = { - "http.method": "UNKNOWN", + "http.method": "_OTHER", "http.host": "localhost", "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, } self._assert_basic_metric( expected_duration_attributes, @@ -410,6 +417,7 @@ def test_basic_metric_nonstandard_http_method_allowed_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 405, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "NONSTANDARD", @@ -417,6 +425,8 @@ def test_basic_metric_nonstandard_http_method_allowed_success(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, } self._assert_basic_metric( expected_duration_attributes, diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py index 2c3ec85e18..4715e0b461 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py @@ -18,6 +18,10 @@ from pyramid.config import Configurator from opentelemetry import trace +from opentelemetry.instrumentation._semconv import ( + _server_active_requests_count_attrs_old, + _server_duration_attrs_old, +) from opentelemetry.instrumentation.pyramid import PyramidInstrumentor from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, @@ -31,8 +35,6 @@ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, - _active_requests_count_attrs, - _duration_attrs, ) # pylint: disable=import-error @@ -43,8 +45,8 @@ "http.server.duration", ] _recommended_attrs = { - "http.server.active_requests": _active_requests_count_attrs, - "http.server.duration": _duration_attrs, + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, } @@ -213,6 +215,7 @@ def test_basic_metric_success(self): "http.server_name": "localhost", "net.host.port": 80, "http.status_code": 200, + "net.host.name": "localhost", } expected_requests_count_attributes = { "http.method": "GET", @@ -220,6 +223,8 @@ def test_basic_metric_success(self): "http.scheme": "http", "http.flavor": "1.1", "http.server_name": "localhost", + "net.host.name": "localhost", + "net.host.port": 80, } metrics_list = self.memory_metrics_reader.get_metrics_data() for metric in ( diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py index 478eab1937..c566c301d8 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py @@ -37,6 +37,7 @@ def expected_attributes(override_attributes): SpanAttributes.HTTP_SERVER_NAME: "localhost", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, + SpanAttributes.NET_HOST_NAME: "localhost", SpanAttributes.HTTP_HOST: "localhost", SpanAttributes.HTTP_TARGET: "/", SpanAttributes.HTTP_FLAVOR: "1.1", diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index d0150d57b7..2052fe47cd 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -63,18 +63,20 @@ _SPAN_ATTRIBUTES_ERROR_TYPE, _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS, _SPAN_ATTRIBUTES_NETWORK_PEER_PORT, - _filter_duration_attrs, + _client_duration_attrs_new, + _client_duration_attrs_old, + _filter_semconv_duration_attrs, _get_schema_url, + _HTTPStabilityMode, _OpenTelemetrySemanticConventionStability, - _OpenTelemetryStabilityMode, _OpenTelemetryStabilitySignalType, _report_new, _report_old, - _set_http_hostname, + _set_http_host, _set_http_method, - _set_http_net_peer_name, + _set_http_net_peer_name_client, _set_http_network_protocol_version, - _set_http_port, + _set_http_peer_port_client, _set_http_scheme, _set_http_status_code, _set_http_url, @@ -117,7 +119,7 @@ def _instrument( request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, excluded_urls: ExcludeList = None, - sem_conv_opt_in_mode: _OpenTelemetryStabilityMode = _OpenTelemetryStabilityMode.DEFAULT, + sem_conv_opt_in_mode: _HTTPStabilityMode = _HTTPStabilityMode.DEFAULT, ): """Enables tracing of all requests calls that go through :code:`requests.session.Session.request` (this includes @@ -174,14 +176,14 @@ def get_or_create_headers(): metric_labels, parsed_url.scheme, sem_conv_opt_in_mode ) if parsed_url.hostname: - _set_http_hostname( + _set_http_host( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) - _set_http_net_peer_name( + _set_http_net_peer_name_client( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode ) if _report_new(sem_conv_opt_in_mode): - _set_http_hostname( + _set_http_host( span_attributes, parsed_url.hostname, sem_conv_opt_in_mode, @@ -191,11 +193,11 @@ def get_or_create_headers(): _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS ] = parsed_url.hostname if parsed_url.port: - _set_http_port( + _set_http_peer_port_client( metric_labels, parsed_url.port, sem_conv_opt_in_mode ) if _report_new(sem_conv_opt_in_mode): - _set_http_port( + _set_http_peer_port_client( span_attributes, parsed_url.port, sem_conv_opt_in_mode ) # Use semconv library when available @@ -284,16 +286,22 @@ def get_or_create_headers(): ).__qualname__ if duration_histogram_old is not None: - duration_attrs_old = _filter_duration_attrs( - metric_labels, _OpenTelemetryStabilityMode.DEFAULT + duration_attrs_old = _filter_semconv_duration_attrs( + metric_labels, + _client_duration_attrs_old, + _client_duration_attrs_new, + _HTTPStabilityMode.DEFAULT, ) duration_histogram_old.record( max(round(elapsed_time * 1000), 0), attributes=duration_attrs_old, ) if duration_histogram_new is not None: - duration_attrs_new = _filter_duration_attrs( - metric_labels, _OpenTelemetryStabilityMode.HTTP + duration_attrs_new = _filter_semconv_duration_attrs( + metric_labels, + _client_duration_attrs_old, + _client_duration_attrs_new, + _HTTPStabilityMode.HTTP, ) duration_histogram_new.record( elapsed_time, attributes=duration_attrs_new @@ -341,7 +349,10 @@ def get_default_span_name(method): Returns: span name """ - return sanitize_method(method.upper().strip()) + method = sanitize_method(method.upper().strip()) + if method == "_OTHER": + return "HTTP" + return method class RequestsInstrumentor(BaseInstrumentor): diff --git a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py index 8817053068..d85d70e20e 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py +++ b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py @@ -23,10 +23,10 @@ import opentelemetry.instrumentation.requests from opentelemetry import trace from opentelemetry.instrumentation._semconv import ( - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY, _SPAN_ATTRIBUTES_ERROR_TYPE, _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS, _SPAN_ATTRIBUTES_NETWORK_PEER_PORT, + OTEL_SEMCONV_STABILITY_OPT_IN, _OpenTelemetrySemanticConventionStability, ) from opentelemetry.instrumentation.requests import RequestsInstrumentor @@ -88,7 +88,7 @@ def setUp(self): "os.environ", { "OTEL_PYTHON_REQUESTS_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg", - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY: sem_conv_mode, + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) @@ -524,7 +524,6 @@ def test_requests_exception_new_semconv(self, *_, **__): self.perform_request(url_with_port) span = self.assert_span() - print(span.attributes) self.assertEqual( span.attributes, { @@ -671,7 +670,7 @@ def setUp(self): self.env_patch = mock.patch.dict( "os.environ", { - _OTEL_SEMCONV_STABILITY_OPT_IN_KEY: sem_conv_mode, + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) self.env_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index 50d4f03dff..0a873d0fc3 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -213,10 +213,34 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he from timeit import default_timer from opentelemetry import context, trace -from opentelemetry.instrumentation.utils import ( - _start_internal_or_server_span, - http_status_to_status_code, +from opentelemetry.instrumentation._semconv import ( + _METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + _SPAN_ATTRIBUTES_ERROR_TYPE, + _filter_semconv_active_request_count_attr, + _filter_semconv_duration_attrs, + _get_schema_url, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _OpenTelemetryStabilitySignalType, + _report_new, + _report_old, + _server_active_requests_count_attrs_new, + _server_active_requests_count_attrs_old, + _server_duration_attrs_new, + _server_duration_attrs_old, + _set_http_flavor_version, + _set_http_method, + _set_http_net_host, + _set_http_net_host_port, + _set_http_net_peer_name_server, + _set_http_peer_ip, + _set_http_peer_port_server, + _set_http_scheme, + _set_http_target, + _set_http_user_agent, + _set_status, ) +from opentelemetry.instrumentation.utils import _start_internal_or_server_span from opentelemetry.instrumentation.wsgi.version import __version__ from opentelemetry.metrics import get_meter from opentelemetry.propagators.textmap import Getter @@ -228,6 +252,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, SanitizeValue, + _parse_url_query, get_custom_headers, normalise_request_header_name, normalise_response_header_name, @@ -239,26 +264,6 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he _CARRIER_KEY_PREFIX = "HTTP_" _CARRIER_KEY_PREFIX_LEN = len(_CARRIER_KEY_PREFIX) -# List of recommended attributes -_duration_attrs = [ - SpanAttributes.HTTP_METHOD, - SpanAttributes.HTTP_HOST, - SpanAttributes.HTTP_SCHEME, - SpanAttributes.HTTP_STATUS_CODE, - SpanAttributes.HTTP_FLAVOR, - SpanAttributes.HTTP_SERVER_NAME, - SpanAttributes.NET_HOST_NAME, - SpanAttributes.NET_HOST_PORT, -] - -_active_requests_count_attrs = [ - SpanAttributes.HTTP_METHOD, - SpanAttributes.HTTP_HOST, - SpanAttributes.HTTP_SCHEME, - SpanAttributes.HTTP_FLAVOR, - SpanAttributes.HTTP_SERVER_NAME, -] - class WSGIGetter(Getter[dict]): def get( @@ -296,53 +301,84 @@ def setifnotnone(dic, key, value): dic[key] = value -def collect_request_attributes(environ): +# pylint: disable=too-many-branches + + +def collect_request_attributes( + environ, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): """Collects HTTP request attributes from the PEP3333-conforming WSGI environ and returns a dictionary to be used as span creation attributes. """ + result = {} + _set_http_method( + result, + environ.get("REQUEST_METHOD", ""), + sanitize_method(environ.get("REQUEST_METHOD", "")), + sem_conv_opt_in_mode, + ) + # old semconv v1.12.0 + server_name = environ.get("SERVER_NAME") + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_SERVER_NAME] = server_name + + _set_http_scheme( + result, + environ.get("wsgi.url_scheme"), + sem_conv_opt_in_mode, + ) - result = { - SpanAttributes.HTTP_METHOD: sanitize_method( - environ.get("REQUEST_METHOD") - ), - SpanAttributes.HTTP_SERVER_NAME: environ.get("SERVER_NAME"), - SpanAttributes.HTTP_SCHEME: environ.get("wsgi.url_scheme"), - } - + host = environ.get("HTTP_HOST") host_port = environ.get("SERVER_PORT") - if host_port is not None and not host_port == "": - result.update({SpanAttributes.NET_HOST_PORT: int(host_port)}) + if host: + _set_http_net_host(result, host, sem_conv_opt_in_mode) + # old semconv v1.12.0 + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_HOST] = host + if host_port: + _set_http_net_host_port( + result, + int(host_port), + sem_conv_opt_in_mode, + ) - setifnotnone(result, SpanAttributes.HTTP_HOST, environ.get("HTTP_HOST")) target = environ.get("RAW_URI") if target is None: # Note: `"" or None is None` target = environ.get("REQUEST_URI") - if target is not None: - result[SpanAttributes.HTTP_TARGET] = target + if target: + path, query = _parse_url_query(target) + _set_http_target(result, target, path, query, sem_conv_opt_in_mode) else: - result[SpanAttributes.HTTP_URL] = remove_url_credentials( - wsgiref_util.request_uri(environ) - ) + # old semconv v1.20.0 + if _report_old(sem_conv_opt_in_mode): + result[SpanAttributes.HTTP_URL] = remove_url_credentials( + wsgiref_util.request_uri(environ) + ) remote_addr = environ.get("REMOTE_ADDR") if remote_addr: - result[SpanAttributes.NET_PEER_IP] = remote_addr + _set_http_peer_ip(result, remote_addr, sem_conv_opt_in_mode) + + peer_port = environ.get("REMOTE_PORT") + if peer_port: + _set_http_peer_port_server(result, peer_port, sem_conv_opt_in_mode) + remote_host = environ.get("REMOTE_HOST") if remote_host and remote_host != remote_addr: - result[SpanAttributes.NET_PEER_NAME] = remote_host + _set_http_net_peer_name_server( + result, remote_host, sem_conv_opt_in_mode + ) user_agent = environ.get("HTTP_USER_AGENT") if user_agent is not None and len(user_agent) > 0: - result[SpanAttributes.HTTP_USER_AGENT] = user_agent + _set_http_user_agent(result, user_agent, sem_conv_opt_in_mode) - setifnotnone( - result, SpanAttributes.NET_PEER_PORT, environ.get("REMOTE_PORT") - ) flavor = environ.get("SERVER_PROTOCOL", "") if flavor.upper().startswith(_HTTP_VERSION_PREFIX): flavor = flavor[len(_HTTP_VERSION_PREFIX) :] if flavor: - result[SpanAttributes.HTTP_FLAVOR] = flavor + _set_http_flavor_version(result, flavor, sem_conv_opt_in_mode) return result @@ -410,46 +446,56 @@ def _parse_status_code(resp_status): return None -def _parse_active_request_count_attrs(req_attrs): - active_requests_count_attrs = {} - for attr_key in _active_requests_count_attrs: - if req_attrs.get(attr_key) is not None: - active_requests_count_attrs[attr_key] = req_attrs[attr_key] - return active_requests_count_attrs +def _parse_active_request_count_attrs( + req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT +): + return _filter_semconv_active_request_count_attr( + req_attrs, + _server_active_requests_count_attrs_old, + _server_active_requests_count_attrs_new, + sem_conv_opt_in_mode, + ) -def _parse_duration_attrs(req_attrs): - duration_attrs = {} - for attr_key in _duration_attrs: - if req_attrs.get(attr_key) is not None: - duration_attrs[attr_key] = req_attrs[attr_key] - return duration_attrs +def _parse_duration_attrs( + req_attrs, sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT +): + return _filter_semconv_duration_attrs( + req_attrs, + _server_duration_attrs_old, + _server_duration_attrs_new, + sem_conv_opt_in_mode, + ) def add_response_attributes( - span, start_response_status, response_headers + span, + start_response_status, + response_headers, + duration_attrs=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, ): # pylint: disable=unused-argument """Adds HTTP response attributes to span using the arguments passed to a PEP3333-conforming start_response callable. """ if not span.is_recording(): return - status_code, _ = start_response_status.split(" ", 1) + status_code_str, _ = start_response_status.split(" ", 1) + status_code = 0 try: - status_code = int(status_code) + status_code = int(status_code_str) except ValueError: - span.set_status( - Status( - StatusCode.ERROR, - "Non-integer HTTP status: " + repr(status_code), - ) - ) - else: - span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - span.set_status( - Status(http_status_to_status_code(status_code, server_span=True)) - ) + status_code = -1 + if duration_attrs is None: + duration_attrs = {} + _set_status( + span, + duration_attrs, + status_code_str, + status_code, + sem_conv_opt_in_mode, + ) def get_default_span_name(environ): @@ -464,6 +510,8 @@ def get_default_span_name(environ): The span name. """ method = sanitize_method(environ.get("REQUEST_METHOD", "").strip()) + if method == "_OTHER": + return "HTTP" path = environ.get("PATH_INFO", "").strip() if method and path: return f"{method} {path}" @@ -495,42 +543,66 @@ def __init__( tracer_provider=None, meter_provider=None, ): + # initialize semantic conventions opt-in if needed + _OpenTelemetrySemanticConventionStability._initialize() + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) self.wsgi = wsgi self.tracer = trace.get_tracer( __name__, __version__, tracer_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) self.meter = get_meter( __name__, __version__, meter_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", - ) - self.duration_histogram = self.meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) + self.duration_histogram_old = None + if _report_old(sem_conv_opt_in_mode): + self.duration_histogram_old = self.meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + self.duration_histogram_new = None + if _report_new(sem_conv_opt_in_mode): + self.duration_histogram_new = self.meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) + # We don't need a separate active request counter for old/new semantic conventions + # because the new attributes are a subset of the old attributes self.active_requests_counter = self.meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, - unit="requests", - description="measures the number of concurrent HTTP requests that are currently in-flight", + unit="{request}", + description="Number of active HTTP server requests.", ) self.request_hook = request_hook self.response_hook = response_hook + self._sem_conv_opt_in_mode = sem_conv_opt_in_mode @staticmethod def _create_start_response( - span, start_response, response_hook, duration_attrs + span, + start_response, + response_hook, + duration_attrs, + sem_conv_opt_in_mode, ): @functools.wraps(start_response) def _start_response(status, response_headers, *args, **kwargs): - add_response_attributes(span, status, response_headers) - status_code = _parse_status_code(status) - if status_code is not None: - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = status_code + add_response_attributes( + span, + status, + response_headers, + duration_attrs, + sem_conv_opt_in_mode, + ) if span.is_recording() and span.kind == trace.SpanKind.SERVER: custom_attributes = collect_custom_response_headers_attributes( response_headers @@ -551,11 +623,13 @@ def __call__(self, environ, start_response): environ: A WSGI environment. start_response: The WSGI start_response callable. """ - req_attrs = collect_request_attributes(environ) + req_attrs = collect_request_attributes( + environ, self._sem_conv_opt_in_mode + ) active_requests_count_attrs = _parse_active_request_count_attrs( - req_attrs + req_attrs, + self._sem_conv_opt_in_mode, ) - duration_attrs = _parse_duration_attrs(req_attrs) span, token = _start_internal_or_server_span( tracer=self.tracer, @@ -584,20 +658,42 @@ def __call__(self, environ, start_response): try: with trace.use_span(span): start_response = self._create_start_response( - span, start_response, response_hook, duration_attrs + span, + start_response, + response_hook, + req_attrs, + self._sem_conv_opt_in_mode, ) iterable = self.wsgi(environ, start_response) return _end_span_after_iterating(iterable, span, token) except Exception as ex: - if span.is_recording(): + if _report_new(self._sem_conv_opt_in_mode): + req_attrs[_SPAN_ATTRIBUTES_ERROR_TYPE] = type(ex).__qualname__ + if span.is_recording(): + span.set_attribute( + _SPAN_ATTRIBUTES_ERROR_TYPE, type(ex).__qualname__ + ) span.set_status(Status(StatusCode.ERROR, str(ex))) span.end() if token is not None: context.detach(token) raise finally: - duration = max(round((default_timer() - start) * 1000), 0) - self.duration_histogram.record(duration, duration_attrs) + duration_s = default_timer() - start + if self.duration_histogram_old: + duration_attrs_old = _parse_duration_attrs( + req_attrs, _HTTPStabilityMode.DEFAULT + ) + self.duration_histogram_old.record( + max(round(duration_s * 1000), 0), duration_attrs_old + ) + if self.duration_histogram_new: + duration_attrs_new = _parse_duration_attrs( + req_attrs, _HTTPStabilityMode.HTTP + ) + self.duration_histogram_new.record( + max(duration_s, 0), duration_attrs_new + ) self.active_requests_counter.add(-1, active_requests_count_attrs) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index f74dd67867..985fbe0571 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-lines + import sys import unittest import wsgiref.util as wsgiref_util @@ -20,6 +22,15 @@ import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import trace as trace_api +from opentelemetry.instrumentation._semconv import ( + OTEL_SEMCONV_STABILITY_OPT_IN, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _server_active_requests_count_attrs_new, + _server_active_requests_count_attrs_old, + _server_duration_attrs_new, + _server_duration_attrs_old, +) from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, NumberDataPoint, @@ -127,17 +138,58 @@ def wsgi_with_repeat_custom_response_headers(environ, start_response): return [b"*"] -_expected_metric_names = [ +_expected_metric_names_old = [ "http.server.active_requests", "http.server.duration", ] -_recommended_attrs = { - "http.server.active_requests": otel_wsgi._active_requests_count_attrs, - "http.server.duration": otel_wsgi._duration_attrs, +_expected_metric_names_new = [ + "http.server.active_requests", + "http.server.request.duration", +] +_recommended_metrics_attrs_old = { + "http.server.active_requests": _server_active_requests_count_attrs_old, + "http.server.duration": _server_duration_attrs_old, +} +_recommended_metrics_attrs_new = { + "http.server.active_requests": _server_active_requests_count_attrs_new, + "http.server.request.duration": _server_duration_attrs_new, +} +_server_active_requests_count_attrs_both = ( + _server_active_requests_count_attrs_old +) +_server_active_requests_count_attrs_both.extend( + _server_active_requests_count_attrs_new +) +_recommended_metrics_attrs_both = { + "http.server.active_requests": _server_active_requests_count_attrs_both, + "http.server.duration": _server_duration_attrs_old, + "http.server.request.duration": _server_duration_attrs_new, } class TestWsgiApplication(WsgiTestBase): + def setUp(self): + super().setUp() + + test_name = "" + if hasattr(self, "_testMethodName"): + test_name = self._testMethodName + sem_conv_mode = "default" + if "new_semconv" in test_name: + sem_conv_mode = "http" + elif "both_semconv" in test_name: + sem_conv_mode = "http/dup" + self.env_patch = mock.patch.dict( + "os.environ", + { + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, + }, + ) + + _OpenTelemetrySemanticConventionStability._initialized = False + + self.env_patch.start() + def validate_response( self, response, @@ -146,6 +198,8 @@ def validate_response( http_method="GET", span_attributes=None, response_headers=None, + old_sem_conv=True, + new_sem_conv=False, ): while True: try: @@ -171,7 +225,8 @@ def validate_response( self.assertEqual(len(span_list), 1) self.assertEqual(span_list[0].name, span_name) self.assertEqual(span_list[0].kind, trace_api.SpanKind.SERVER) - expected_attributes = { + expected_attributes = {} + expected_attributes_old = { SpanAttributes.HTTP_SERVER_NAME: "127.0.0.1", SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.NET_HOST_PORT: 80, @@ -179,10 +234,27 @@ def validate_response( SpanAttributes.HTTP_FLAVOR: "1.0", SpanAttributes.HTTP_URL: "http://127.0.0.1/", SpanAttributes.HTTP_STATUS_CODE: 200, + SpanAttributes.NET_HOST_NAME: "127.0.0.1", } + expected_attributes_new = { + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.SERVER_ADDRESS: "127.0.0.1", + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200, + } + if old_sem_conv: + expected_attributes.update(expected_attributes_old) + if new_sem_conv: + expected_attributes.update(expected_attributes_new) + expected_attributes.update(span_attributes or {}) if http_method is not None: - expected_attributes[SpanAttributes.HTTP_METHOD] = http_method + if old_sem_conv: + expected_attributes[SpanAttributes.HTTP_METHOD] = http_method + if new_sem_conv: + expected_attributes[ + SpanAttributes.HTTP_REQUEST_METHOD + ] = http_method self.assertEqual(span_list[0].attributes, expected_attributes) def test_basic_wsgi_call(self): @@ -190,6 +262,16 @@ def test_basic_wsgi_call(self): response = app(self.environ, self.start_response) self.validate_response(response) + def test_basic_wsgi_call_new_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) + response = app(self.environ, self.start_response) + self.validate_response(response, old_sem_conv=False, new_sem_conv=True) + + def test_basic_wsgi_call_both_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) + response = app(self.environ, self.start_response) + self.validate_response(response, old_sem_conv=True, new_sem_conv=True) + def test_hooks(self): hook_headers = ( "hook_attr", @@ -283,7 +365,7 @@ def test_wsgi_metrics(self): for scope_metric in resource_metric.scope_metrics: self.assertTrue(len(scope_metric.metrics) != 0) for metric in scope_metric.metrics: - self.assertIn(metric.name, _expected_metric_names) + self.assertIn(metric.name, _expected_metric_names_old) data_points = list(metric.data.data_points) self.assertEqual(len(data_points), 1) for point in data_points: @@ -294,7 +376,77 @@ def test_wsgi_metrics(self): number_data_point_seen = True for attr in point.attributes: self.assertIn( - attr, _recommended_attrs[metric.name] + attr, + _recommended_metrics_attrs_old[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_wsgi_metrics_new_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(error_wsgi_unhandled) + self.assertRaises(ValueError, app, self.environ, self.start_response) + self.assertRaises(ValueError, app, self.environ, self.start_response) + self.assertRaises(ValueError, app, self.environ, self.start_response) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names_new) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_new[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_wsgi_metrics_both_semconv(self): + app = otel_wsgi.OpenTelemetryMiddleware(error_wsgi_unhandled) + self.assertRaises(ValueError, app, self.environ, self.start_response) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + if metric.unit == "ms": + self.assertEqual(metric.name, "http.server.duration") + elif metric.unit == "s": + self.assertEqual( + metric.name, "http.server.request.duration" + ) + else: + self.assertEqual( + metric.name, "http.server.active_requests" + ) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 1) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_both[metric.name], ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) @@ -303,7 +455,7 @@ def test_nonstandard_http_method(self): app = otel_wsgi.OpenTelemetryMiddleware(simple_wsgi) response = app(self.environ, self.start_response) self.validate_response( - response, span_name="UNKNOWN /", http_method="UNKNOWN" + response, span_name="HTTP", http_method="_OTHER" ) @mock.patch.dict( @@ -349,34 +501,95 @@ def test_request_attributes(self): SpanAttributes.HTTP_SCHEME: "http", SpanAttributes.HTTP_SERVER_NAME: "127.0.0.1", SpanAttributes.HTTP_FLAVOR: "1.0", + SpanAttributes.NET_HOST_NAME: "127.0.0.1", + }, + ) + + def test_request_attributes_new_semconv(self): + self.environ["QUERY_STRING"] = "foo=bar" + self.environ["REQUEST_URI"] = "http://127.0.0.1/?foo=bar" + + attrs = otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ) + self.assertDictEqual( + attrs, + { + SpanAttributes.HTTP_REQUEST_METHOD: "GET", + SpanAttributes.SERVER_ADDRESS: "127.0.0.1", + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", + SpanAttributes.URL_PATH: "/", + SpanAttributes.URL_QUERY: "foo=bar", }, ) - def validate_url(self, expected_url, raw=False, has_host=True): + def validate_url( + self, + expected_url, + raw=False, + has_host=True, + old_semconv=True, + new_semconv=False, + ): parts = urlsplit(expected_url) - expected = { + expected_old = { SpanAttributes.HTTP_SCHEME: parts.scheme, SpanAttributes.NET_HOST_PORT: parts.port or (80 if parts.scheme == "http" else 443), SpanAttributes.HTTP_SERVER_NAME: parts.hostname, # Not true in the general case, but for all tests. } - if raw: - expected[SpanAttributes.HTTP_TARGET] = expected_url.split( - parts.netloc, 1 - )[1] - else: - expected[SpanAttributes.HTTP_URL] = expected_url - if has_host: - expected[SpanAttributes.HTTP_HOST] = parts.hostname + expected_new = { + SpanAttributes.SERVER_PORT: parts.port + or (80 if parts.scheme == "http" else 443), + SpanAttributes.SERVER_ADDRESS: parts.hostname, + SpanAttributes.URL_PATH: parts.path, + SpanAttributes.URL_QUERY: parts.query, + } + if old_semconv: + if raw: + expected_old[SpanAttributes.HTTP_TARGET] = expected_url.split( + parts.netloc, 1 + )[1] + else: + expected_old[SpanAttributes.HTTP_URL] = expected_url + if has_host: + expected_old[SpanAttributes.HTTP_HOST] = parts.hostname + if new_semconv: + if raw: + expected_new[SpanAttributes.URL_PATH] = expected_url.split( + parts.path, 1 + )[1] + if parts.query: + expected_new[ + SpanAttributes.URL_QUERY + ] = expected_url.split(parts.query, 1)[1] + else: + expected_new[SpanAttributes.HTTP_URL] = expected_url + if has_host: + expected_new[SpanAttributes.SERVER_ADDRESS] = parts.hostname attrs = otel_wsgi.collect_request_attributes(self.environ) self.assertGreaterEqual( - attrs.items(), expected.items(), expected_url + " expected." + attrs.items(), expected_old.items(), expected_url + " expected." ) def test_request_attributes_with_partial_raw_uri(self): - self.environ["RAW_URI"] = "/#top" - self.validate_url("http://127.0.0.1/#top", raw=True) + self.environ["RAW_URI"] = "/?foo=bar/#top" + self.validate_url("http://127.0.0.1/?foo=bar/#top", raw=True) + self.validate_url( + "http://127.0.0.1/?foo=bar/#top", + raw=True, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "http://127.0.0.1/?foo=bar/#top", + raw=True, + old_semconv=True, + new_semconv=True, + ) def test_request_attributes_with_partial_raw_uri_and_nonstandard_port( self, @@ -385,18 +598,68 @@ def test_request_attributes_with_partial_raw_uri_and_nonstandard_port( del self.environ["HTTP_HOST"] self.environ["SERVER_PORT"] = "8080" self.validate_url("http://127.0.0.1:8080/?", raw=True, has_host=False) + self.validate_url( + "http://127.0.0.1:8080/?", + raw=True, + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "http://127.0.0.1:8080/?", + raw=True, + has_host=False, + old_semconv=True, + new_semconv=True, + ) def test_https_uri_port(self): del self.environ["HTTP_HOST"] self.environ["SERVER_PORT"] = "443" self.environ["wsgi.url_scheme"] = "https" self.validate_url("https://127.0.0.1/", has_host=False) + self.validate_url( + "https://127.0.0.1/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) self.environ["SERVER_PORT"] = "8080" self.validate_url("https://127.0.0.1:8080/", has_host=False) + self.validate_url( + "https://127.0.0.1:8080/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1:8080/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) self.environ["SERVER_PORT"] = "80" self.validate_url("https://127.0.0.1:80/", has_host=False) + self.validate_url( + "https://127.0.0.1:80/", + has_host=False, + old_semconv=False, + new_semconv=True, + ) + self.validate_url( + "https://127.0.0.1:80/", + has_host=False, + old_semconv=True, + new_semconv=True, + ) def test_http_uri_port(self): del self.environ["HTTP_HOST"] @@ -438,10 +701,10 @@ def test_request_attributes_with_faux_scheme_relative_raw_uri(self): def test_request_attributes_pathless(self): self.environ["RAW_URI"] = "" - expected = {SpanAttributes.HTTP_TARGET: ""} - self.assertGreaterEqual( - otel_wsgi.collect_request_attributes(self.environ).items(), - expected.items(), + self.assertIsNone( + otel_wsgi.collect_request_attributes(self.environ).get( + SpanAttributes.HTTP_TARGET + ) ) def test_request_attributes_with_full_request_uri(self): @@ -449,29 +712,58 @@ def test_request_attributes_with_full_request_uri(self): self.environ["REQUEST_METHOD"] = "CONNECT" self.environ[ "REQUEST_URI" - ] = "127.0.0.1:8080" # Might happen in a CONNECT request - expected = { + ] = "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing" # Might happen in a CONNECT request + expected_old = { SpanAttributes.HTTP_HOST: "127.0.0.1:8080", - SpanAttributes.HTTP_TARGET: "127.0.0.1:8080", + SpanAttributes.HTTP_TARGET: "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing", + } + expected_new = { + SpanAttributes.URL_PATH: "/3/library/urllib.parse.html", + SpanAttributes.URL_QUERY: "highlight=params", } self.assertGreaterEqual( otel_wsgi.collect_request_attributes(self.environ).items(), - expected.items(), + expected_old.items(), + ) + self.assertGreaterEqual( + otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ).items(), + expected_new.items(), ) def test_http_user_agent_attribute(self): self.environ["HTTP_USER_AGENT"] = "test-useragent" expected = {SpanAttributes.HTTP_USER_AGENT: "test-useragent"} + expected_new = {SpanAttributes.USER_AGENT_ORIGINAL: "test-useragent"} self.assertGreaterEqual( otel_wsgi.collect_request_attributes(self.environ).items(), expected.items(), ) + self.assertGreaterEqual( + otel_wsgi.collect_request_attributes( + self.environ, + _HTTPStabilityMode.HTTP, + ).items(), + expected_new.items(), + ) def test_response_attributes(self): otel_wsgi.add_response_attributes(self.span, "404 Not Found", {}) + otel_wsgi.add_response_attributes( + self.span, + "404 Not Found", + {}, + sem_conv_opt_in_mode=_HTTPStabilityMode.HTTP, + ) expected = (mock.call(SpanAttributes.HTTP_STATUS_CODE, 404),) - self.assertEqual(self.span.set_attribute.call_count, len(expected)) + expected_new = ( + mock.call(SpanAttributes.HTTP_RESPONSE_STATUS_CODE, 404), + ) + self.assertEqual(self.span.set_attribute.call_count, 2) self.span.set_attribute.assert_has_calls(expected, any_order=True) + self.span.set_attribute.assert_has_calls(expected_new, any_order=True) def test_credential_removal(self): self.environ["HTTP_HOST"] = "username:password@mock" diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index fbfc92cf21..31c2486acc 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -16,13 +16,16 @@ import threading from enum import Enum +from opentelemetry.instrumentation.utils import http_status_to_status_code from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace.status import Status, StatusCode # TODO: will come through semconv package once updated _SPAN_ATTRIBUTES_ERROR_TYPE = "error.type" _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS = "network.peer.address" _SPAN_ATTRIBUTES_NETWORK_PEER_PORT = "network.peer.port" _METRIC_ATTRIBUTES_CLIENT_DURATION_NAME = "http.client.request.duration" +_METRIC_ATTRIBUTES_SERVER_DURATION_NAME = "http.server.request.duration" _client_duration_attrs_old = [ SpanAttributes.HTTP_STATUS_CODE, @@ -45,13 +48,117 @@ # SpanAttributes.URL_SCHEME, ] +_server_duration_attrs_old = [ + SpanAttributes.HTTP_METHOD, + SpanAttributes.HTTP_HOST, + SpanAttributes.HTTP_SCHEME, + SpanAttributes.HTTP_STATUS_CODE, + SpanAttributes.HTTP_FLAVOR, + SpanAttributes.HTTP_SERVER_NAME, + SpanAttributes.NET_HOST_NAME, + SpanAttributes.NET_HOST_PORT, +] + +_server_duration_attrs_new = [ + _SPAN_ATTRIBUTES_ERROR_TYPE, + SpanAttributes.HTTP_REQUEST_METHOD, + SpanAttributes.HTTP_RESPONSE_STATUS_CODE, + SpanAttributes.HTTP_ROUTE, + SpanAttributes.NETWORK_PROTOCOL_VERSION, + # TODO: Support opt-in for scheme in new semconv + # SpanAttributes.URL_SCHEME, +] + +_server_active_requests_count_attrs_old = [ + SpanAttributes.HTTP_METHOD, + SpanAttributes.HTTP_HOST, + SpanAttributes.HTTP_SCHEME, + SpanAttributes.HTTP_FLAVOR, + SpanAttributes.HTTP_SERVER_NAME, + SpanAttributes.NET_HOST_NAME, + SpanAttributes.NET_HOST_PORT, +] + +_server_active_requests_count_attrs_new = [ + SpanAttributes.HTTP_REQUEST_METHOD, + SpanAttributes.URL_SCHEME, +] + +OTEL_SEMCONV_STABILITY_OPT_IN = "OTEL_SEMCONV_STABILITY_OPT_IN" + + +class _OpenTelemetryStabilitySignalType: + HTTP = "http" + + +class _HTTPStabilityMode(Enum): + # http - emit the new, stable HTTP and networking conventions ONLY + HTTP = "http" + # http/dup - emit both the old and the stable HTTP and networking conventions + HTTP_DUP = "http/dup" + # default - continue emitting old experimental HTTP and networking conventions + DEFAULT = "default" + + +def _report_new(mode): + return mode.name != _HTTPStabilityMode.DEFAULT.name + + +def _report_old(mode): + return mode.name != _HTTPStabilityMode.HTTP.name -def _filter_duration_attrs(attrs, sem_conv_opt_in_mode): + +class _OpenTelemetrySemanticConventionStability: + _initialized = False + _lock = threading.Lock() + _OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {} + + @classmethod + def _initialize(cls): + with _OpenTelemetrySemanticConventionStability._lock: + if not _OpenTelemetrySemanticConventionStability._initialized: + # Users can pass in comma delimited string for opt-in options + # Only values for http stability are supported for now + opt_in = os.environ.get(OTEL_SEMCONV_STABILITY_OPT_IN, "") + opt_in_list = [] + if opt_in: + opt_in_list = [s.strip() for s in opt_in.split(",")] + http_opt_in = _HTTPStabilityMode.DEFAULT + if opt_in_list: + # Process http opt-in + # http/dup takes priority over http + if _HTTPStabilityMode.HTTP_DUP.value in opt_in_list: + http_opt_in = _HTTPStabilityMode.HTTP_DUP + elif _HTTPStabilityMode.HTTP.value in opt_in_list: + http_opt_in = _HTTPStabilityMode.HTTP + _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[ + _OpenTelemetryStabilitySignalType.HTTP + ] = http_opt_in + _OpenTelemetrySemanticConventionStability._initialized = True + + @classmethod + # Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.) + def _get_opentelemetry_stability_opt_in_mode( + cls, + signal_type: _OpenTelemetryStabilitySignalType, + ) -> _HTTPStabilityMode: + return _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get( + signal_type, _HTTPStabilityMode.DEFAULT + ) + + +def _filter_semconv_duration_attrs( + attrs, + old_attrs, + new_attrs, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): filtered_attrs = {} + # duration is two different metrics depending on sem_conv_opt_in_mode, so no DUP attributes allowed_attributes = ( - _client_duration_attrs_new - if sem_conv_opt_in_mode == _OpenTelemetryStabilityMode.HTTP - else _client_duration_attrs_old + new_attrs + if sem_conv_opt_in_mode == _HTTPStabilityMode.HTTP + else old_attrs ) for key, val in attrs.items(): if key in allowed_attributes: @@ -59,6 +166,24 @@ def _filter_duration_attrs(attrs, sem_conv_opt_in_mode): return filtered_attrs +def _filter_semconv_active_request_count_attr( + attrs, + old_attrs, + new_attrs, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, +): + filtered_attrs = {} + if _report_old(sem_conv_opt_in_mode): + for key, val in attrs.items(): + if key in old_attrs: + filtered_attrs[key] = val + if _report_new(sem_conv_opt_in_mode): + for key, val in attrs.items(): + if key in new_attrs: + filtered_attrs[key] = val + return filtered_attrs + + def set_string_attribute(result, key, value): if value: result[key] = value @@ -90,6 +215,15 @@ def _set_http_method(result, original, normalized, sem_conv_opt_in_mode): ) +def _set_http_status_code(result, code, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.HTTP_STATUS_CODE, code) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute( + result, SpanAttributes.HTTP_RESPONSE_STATUS_CODE, code + ) + + def _set_http_url(result, url, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_URL, url) @@ -105,36 +239,30 @@ def _set_http_scheme(result, scheme, sem_conv_opt_in_mode): # set_string_attribute(result, SpanAttributes.URL_SCHEME, scheme) -def _set_http_hostname(result, hostname, sem_conv_opt_in_mode): +def _set_http_host(result, host, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): - set_string_attribute(result, SpanAttributes.HTTP_HOST, hostname) + set_string_attribute(result, SpanAttributes.HTTP_HOST, host) if _report_new(sem_conv_opt_in_mode): - set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, hostname) + set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, host) + +# Client -def _set_http_net_peer_name(result, peer_name, sem_conv_opt_in_mode): + +def _set_http_net_peer_name_client(result, peer_name, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.NET_PEER_NAME, peer_name) if _report_new(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, peer_name) -def _set_http_port(result, port, sem_conv_opt_in_mode): +def _set_http_peer_port_client(result, port, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_int_attribute(result, SpanAttributes.NET_PEER_PORT, port) if _report_new(sem_conv_opt_in_mode): set_int_attribute(result, SpanAttributes.SERVER_PORT, port) -def _set_http_status_code(result, code, sem_conv_opt_in_mode): - if _report_old(sem_conv_opt_in_mode): - set_int_attribute(result, SpanAttributes.HTTP_STATUS_CODE, code) - if _report_new(sem_conv_opt_in_mode): - set_int_attribute( - result, SpanAttributes.HTTP_RESPONSE_STATUS_CODE, code - ) - - def _set_http_network_protocol_version(result, version, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_FLAVOR, version) @@ -144,74 +272,117 @@ def _set_http_network_protocol_version(result, version, sem_conv_opt_in_mode): ) -_OTEL_SEMCONV_STABILITY_OPT_IN_KEY = "OTEL_SEMCONV_STABILITY_OPT_IN" +# Server -class _OpenTelemetryStabilitySignalType: - HTTP = "http" +def _set_http_net_host(result, host, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_HOST_NAME, host) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.SERVER_ADDRESS, host) -class _OpenTelemetryStabilityMode(Enum): - # http - emit the new, stable HTTP and networking conventions ONLY - HTTP = "http" - # http/dup - emit both the old and the stable HTTP and networking conventions - HTTP_DUP = "http/dup" - # default - continue emitting old experimental HTTP and networking conventions - DEFAULT = "default" +def _set_http_net_host_port(result, port, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.NET_HOST_PORT, port) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.SERVER_PORT, port) -def _report_new(mode): - return mode.name != _OpenTelemetryStabilityMode.DEFAULT.name +def _set_http_target(result, target, path, query, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.HTTP_TARGET, target) + if _report_new(sem_conv_opt_in_mode): + if path: + set_string_attribute(result, SpanAttributes.URL_PATH, path) + if query: + set_string_attribute(result, SpanAttributes.URL_QUERY, query) -def _report_old(mode): - return mode.name != _OpenTelemetryStabilityMode.HTTP.name +def _set_http_peer_ip(result, ip, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_PEER_IP, ip) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.CLIENT_ADDRESS, ip) -class _OpenTelemetrySemanticConventionStability: - _initialized = False - _lock = threading.Lock() - _OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {} +def _set_http_peer_port_server(result, port, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.NET_PEER_PORT, port) + if _report_new(sem_conv_opt_in_mode): + set_int_attribute(result, SpanAttributes.CLIENT_PORT, port) - @classmethod - def _initialize(cls): - with _OpenTelemetrySemanticConventionStability._lock: - if not _OpenTelemetrySemanticConventionStability._initialized: - # Users can pass in comma delimited string for opt-in options - # Only values for http stability are supported for now - opt_in = os.environ.get(_OTEL_SEMCONV_STABILITY_OPT_IN_KEY, "") - opt_in_list = [] - if opt_in: - opt_in_list = [s.strip() for s in opt_in.split(",")] - http_opt_in = _OpenTelemetryStabilityMode.DEFAULT - if opt_in_list: - # Process http opt-in - # http/dup takes priority over http - if ( - _OpenTelemetryStabilityMode.HTTP_DUP.value - in opt_in_list - ): - http_opt_in = _OpenTelemetryStabilityMode.HTTP_DUP - elif _OpenTelemetryStabilityMode.HTTP.value in opt_in_list: - http_opt_in = _OpenTelemetryStabilityMode.HTTP - _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[ - _OpenTelemetryStabilitySignalType.HTTP - ] = http_opt_in - _OpenTelemetrySemanticConventionStability._initialized = True - @classmethod - # Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.) - def _get_opentelemetry_stability_opt_in_mode( - cls, - signal_type: _OpenTelemetryStabilitySignalType, - ) -> _OpenTelemetryStabilityMode: - return _OpenTelemetrySemanticConventionStability._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get( - signal_type, _OpenTelemetryStabilityMode.DEFAULT +def _set_http_user_agent(result, user_agent, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.HTTP_USER_AGENT, user_agent + ) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.USER_AGENT_ORIGINAL, user_agent + ) + + +def _set_http_net_peer_name_server(result, name, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.NET_PEER_NAME, name) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.CLIENT_ADDRESS, name) + + +def _set_http_flavor_version(result, version, sem_conv_opt_in_mode): + if _report_old(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.HTTP_FLAVOR, version) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute( + result, SpanAttributes.NETWORK_PROTOCOL_VERSION, version + ) + + +def _set_status( + span, + metrics_attributes, + status_code_str, + status_code, + sem_conv_opt_in_mode, +): + if status_code < 0: + if _report_new(sem_conv_opt_in_mode): + span.set_attribute(_SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str) + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = status_code_str + + span.set_status( + Status( + StatusCode.ERROR, + "Non-integer HTTP status: " + status_code_str, + ) ) + else: + status = http_status_to_status_code(status_code, server_span=True) + + if _report_old(sem_conv_opt_in_mode): + span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) + metrics_attributes[SpanAttributes.HTTP_STATUS_CODE] = status_code + if _report_new(sem_conv_opt_in_mode): + span.set_attribute( + SpanAttributes.HTTP_RESPONSE_STATUS_CODE, status_code + ) + metrics_attributes[ + SpanAttributes.HTTP_RESPONSE_STATUS_CODE + ] = status_code + if status == StatusCode.ERROR: + span.set_attribute( + _SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str + ) + metrics_attributes[ + _SPAN_ATTRIBUTES_ERROR_TYPE + ] = status_code_str + span.set_status(Status(status)) # Get schema version based off of opt-in mode -def _get_schema_url(mode: _OpenTelemetryStabilityMode) -> str: - if mode is _OpenTelemetryStabilityMode.DEFAULT: +def _get_schema_url(mode: _HTTPStabilityMode) -> str: + if mode is _HTTPStabilityMode.DEFAULT: return "https://opentelemetry.io/schemas/1.11.0" return SpanAttributes.SCHEMA_URL diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index 523f9400b1..1f7ce98937 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -218,7 +218,7 @@ def sanitize_method(method: Optional[str]) -> Optional[str]: ] ): return method - return "UNKNOWN" + return "_OTHER" def get_custom_headers(env_var: str) -> list[str]: @@ -245,3 +245,10 @@ def _parse_duration_attrs(req_attrs): for key in _duration_attrs.intersection(req_attrs.keys()) } return duration_attrs + + +def _parse_url_query(url: str): + parsed_url = urlparse(url) + path = parsed_url.path + query_params = parsed_url.query + return path, query_params From ad06e7043c6cde838ae0668ddf701827fca4cd51 Mon Sep 17 00:00:00 2001 From: Gal Bashan Date: Sun, 21 Apr 2024 14:11:39 +0300 Subject: [PATCH 11/28] feat(pika): adding support for channel.consume instrumentation (#2397) * feat(pika): adding support for channel.consume instrumentation * updated changelog * wip tests * updating docs * more tests * removing span member on object proxy * adding test for ReadyMessagesDequeProxy * adding tests * better comment on span.end() * fixing docs * ending span even on exceptions --- CHANGELOG.md | 7 ++ .../instrumentation/pika/__init__.py | 9 ++ .../instrumentation/pika/pika_instrumentor.py | 28 ++++- .../instrumentation/pika/utils.py | 83 ++++++++++++- .../tests/test_pika_instrumentation.py | 37 +++++- .../tests/test_utils.py | 116 ++++++++++++++++++ 6 files changed, 274 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6db0e04e68..193779659c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported + only for global, non channel specific instrumentation) + ([#2397](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2397))) + + ### Breaking changes - Rename `type` attribute to `asgi.event.type` in `opentelemetry-instrumentation-asgi` diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py index c745462cf3..d9cec06525 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py @@ -77,6 +77,15 @@ def consume_hook(span: Span, body: bytes, properties: BasicProperties): PikaInstrumentor.instrument_channel(channel, publish_hook=publish_hook, consume_hook=consume_hook) +Consumer Instrumentation +------------------------ +For consumer instrumentation, pika supports two consuming modes: + +* Consumers using the `basic_consume` method which accepts a callback. This is supported for global instrumentation + (`PikaInstrumentor().instrument()`) as well channel specific instrumentation (`PikaInstrumentor().instrument_channel(channel)`) +* Consumers using the `consume` method which returns a generator over messages. This is supported for global + instrumentations only (`PikaInstrumentor().instrument()`) + API --- """ diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py index 56c78a85c3..76261c89ce 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py @@ -20,7 +20,10 @@ import wrapt from packaging import version from pika.adapters import BlockingConnection -from pika.adapters.blocking_connection import BlockingChannel +from pika.adapters.blocking_connection import ( + BlockingChannel, + _QueueConsumerGeneratorInfo, +) from opentelemetry import trace from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -191,6 +194,24 @@ def wrapper(wrapped, instance, args, kwargs): wrapt.wrap_function_wrapper(channel, "basic_consume", wrapper) + @staticmethod + def _decorate_queue_consumer_generator( + tracer_provider: Optional[TracerProvider], + consume_hook: utils.HookT = utils.dummy_callback, + ) -> None: + tracer = trace.get_tracer(__name__, __version__, tracer_provider) + + def wrapper(wrapped, instance, args, kwargs): + res = wrapped(*args, **kwargs) + instance.pending_events = utils.ReadyMessagesDequeProxy( + instance.pending_events, instance, tracer, consume_hook + ) + return res + + wrapt.wrap_function_wrapper( + _QueueConsumerGeneratorInfo, "__init__", wrapper + ) + def _instrument(self, **kwargs: Dict[str, Any]) -> None: tracer_provider: TracerProvider = kwargs.get("tracer_provider", None) publish_hook: utils.HookT = kwargs.get( @@ -207,10 +228,15 @@ def _instrument(self, **kwargs: Dict[str, Any]) -> None: consume_hook=consume_hook, ) + self._decorate_queue_consumer_generator( + tracer_provider, consume_hook=consume_hook + ) + def _uninstrument(self, **kwargs: Dict[str, Any]) -> None: if hasattr(self, "__opentelemetry_tracer_provider"): delattr(self, "__opentelemetry_tracer_provider") unwrap(BlockingConnection, "channel") + unwrap(_QueueConsumerGeneratorInfo, "__init__") def instrumentation_dependencies(self) -> Collection[str]: return _instruments diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py index 6dab4fdfa9..5afa5d9ee6 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py @@ -1,8 +1,13 @@ from logging import getLogger from typing import Any, Callable, List, Optional +from pika.adapters.blocking_connection import ( + _ConsumerDeliveryEvt, + _QueueConsumerGeneratorInfo, +) from pika.channel import Channel from pika.spec import Basic, BasicProperties +from wrapt import ObjectProxy from opentelemetry import context, propagate, trace from opentelemetry.instrumentation.utils import is_instrumentation_enabled @@ -128,7 +133,7 @@ def decorated_function( def _get_span( tracer: Tracer, - channel: Channel, + channel: Optional[Channel], properties: BasicProperties, task_name: str, destination: str, @@ -157,7 +162,7 @@ def _generate_span_name( def _enrich_span( span: Span, - channel: Channel, + channel: Optional[Channel], properties: BasicProperties, task_destination: str, operation: Optional[MessagingOperationValues] = None, @@ -176,6 +181,8 @@ def _enrich_span( span.set_attribute( SpanAttributes.MESSAGING_CONVERSATION_ID, properties.correlation_id ) + if not channel: + return if not hasattr(channel.connection, "params"): span.set_attribute( SpanAttributes.NET_PEER_NAME, channel.connection._impl.params.host @@ -190,3 +197,75 @@ def _enrich_span( span.set_attribute( SpanAttributes.NET_PEER_PORT, channel.connection.params.port ) + + +# pylint:disable=abstract-method +class ReadyMessagesDequeProxy(ObjectProxy): + def __init__( + self, + wrapped, + queue_consumer_generator: _QueueConsumerGeneratorInfo, + tracer: Optional[Tracer], + consume_hook: HookT = dummy_callback, + ): + super().__init__(wrapped) + self._self_active_token = None + self._self_tracer = tracer + self._self_consume_hook = consume_hook + self._self_queue_consumer_generator = queue_consumer_generator + + def popleft(self, *args, **kwargs): + try: + # end active context if exists + if self._self_active_token: + context.detach(self._self_active_token) + except Exception as inst_exception: # pylint: disable=W0703 + _LOG.exception(inst_exception) + + evt = self.__wrapped__.popleft(*args, **kwargs) + + try: + # If a new message was received, create a span and set as active context + if isinstance(evt, _ConsumerDeliveryEvt): + method = evt.method + properties = evt.properties + if not properties: + properties = BasicProperties(headers={}) + if properties.headers is None: + properties.headers = {} + ctx = propagate.extract( + properties.headers, getter=_pika_getter + ) + if not ctx: + ctx = context.get_current() + message_ctx_token = context.attach(ctx) + span = _get_span( + self._self_tracer, + None, + properties, + destination=method.exchange + if method.exchange + else method.routing_key, + span_kind=SpanKind.CONSUMER, + task_name=self._self_queue_consumer_generator.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + try: + context.detach(message_ctx_token) + self._self_active_token = context.attach( + trace.set_span_in_context(span) + ) + self._self_consume_hook(span, evt.body, properties) + except Exception as hook_exception: # pylint: disable=W0703 + _LOG.exception(hook_exception) + finally: + # We must end the span here, because the next place we can hook + # is not the end of the user code, but only when the next message + # arrives. we still set this span's context as the active context + # so spans created by user code that handles this message will be + # children of this one. + span.end() + except Exception as inst_exception: # pylint: disable=W0703 + _LOG.exception(inst_exception) + + return evt diff --git a/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py b/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py index 6e154c04f9..ad519c4a35 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-pika/tests/test_pika_instrumentation.py @@ -14,6 +14,7 @@ from unittest import TestCase, mock from pika.adapters import BlockingConnection +from pika.adapters.blocking_connection import _QueueConsumerGeneratorInfo from pika.channel import Channel from wrapt import BoundFunctionWrapper @@ -21,7 +22,10 @@ from opentelemetry.instrumentation.pika.pika_instrumentor import ( _consumer_callback_attribute_name, ) -from opentelemetry.instrumentation.pika.utils import dummy_callback +from opentelemetry.instrumentation.pika.utils import ( + ReadyMessagesDequeProxy, + dummy_callback, +) from opentelemetry.trace import Tracer @@ -40,13 +44,23 @@ def test_instrument_api(self) -> None: self.assertTrue( isinstance(BlockingConnection.channel, BoundFunctionWrapper) ) + self.assertTrue( + isinstance( + _QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper + ) + ) assert hasattr( instrumentation, "__opentelemetry_tracer_provider" ), "Tracer not stored for the object!" - instrumentation.uninstrument(channel=self.channel) + instrumentation.uninstrument() self.assertFalse( isinstance(BlockingConnection.channel, BoundFunctionWrapper) ) + self.assertFalse( + isinstance( + _QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper + ) + ) @mock.patch( "opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_channel_functions" @@ -57,7 +71,7 @@ def test_instrument_api(self) -> None: @mock.patch( "opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_blocking_channel_consumers" ) - def test_instrument( + def test_instrument_channel( self, instrument_blocking_channel_consumers: mock.MagicMock, instrument_basic_consume: mock.MagicMock, @@ -110,6 +124,23 @@ def test_instrument_basic_publish( self.channel.basic_publish, decorate_basic_publish.return_value ) + def test_instrument_queue_consumer_generator(self) -> None: + instrumentation = PikaInstrumentor() + instrumentation.instrument() + generator_info = _QueueConsumerGeneratorInfo( + params=("queue", False, False), consumer_tag="tag" + ) + self.assertTrue( + isinstance(generator_info.pending_events, ReadyMessagesDequeProxy) + ) + instrumentation.uninstrument() + generator_info = _QueueConsumerGeneratorInfo( + params=("queue", False, False), consumer_tag="tag" + ) + self.assertFalse( + isinstance(generator_info.pending_events, ReadyMessagesDequeProxy) + ) + def test_uninstrument_channel_functions(self) -> None: original_function = self.channel.basic_publish self.channel.basic_publish = mock.MagicMock() diff --git a/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py b/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py index ed33593389..d651ea64c9 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py +++ b/instrumentation/opentelemetry-instrumentation-pika/tests/test_utils.py @@ -11,8 +11,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import collections from unittest import TestCase, mock +from pika.adapters.blocking_connection import ( + _ConsumerCancellationEvt, + _ConsumerDeliveryEvt, + _QueueConsumerGeneratorInfo, +) from pika.channel import Channel from pika.spec import Basic, BasicProperties @@ -448,3 +454,113 @@ def test_decorate_basic_publish_when_span_is_not_recording( exchange_name, routing_key, mock_body, properties, False ) self.assertEqual(retval, callback.return_value) + + # pylint: disable=too-many-statements + @mock.patch("opentelemetry.instrumentation.pika.utils._get_span") + @mock.patch("opentelemetry.propagate.extract") + @mock.patch("opentelemetry.context.detach") + @mock.patch("opentelemetry.context.attach") + @mock.patch("opentelemetry.context.get_current") + def test_decorate_deque_proxy( + self, + context_get_current: mock.MagicMock, + context_attach: mock.MagicMock, + context_detach: mock.MagicMock, + extract: mock.MagicMock, + get_span: mock.MagicMock, + ) -> None: + returned_span = mock.MagicMock() + get_span.return_value = returned_span + consume_hook = mock.MagicMock() + tracer = mock.MagicMock() + generator_info = mock.MagicMock( + spec=_QueueConsumerGeneratorInfo, + pending_events=mock.MagicMock(spec=collections.deque), + consumer_tag="mock_task_name", + ) + method = mock.MagicMock(spec=Basic.Deliver) + method.exchange = "test_exchange" + properties = mock.MagicMock() + evt = _ConsumerDeliveryEvt(method, properties, b"mock_body") + generator_info.pending_events.popleft.return_value = evt + proxy = utils.ReadyMessagesDequeProxy( + generator_info.pending_events, generator_info, tracer, consume_hook + ) + + # First call (no detach cleanup) + res = proxy.popleft() + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_called_once_with( + properties.headers, getter=utils._pika_getter + ) + context_get_current.assert_called_once() + self.assertEqual(context_attach.call_count, 2) + self.assertEqual(context_detach.call_count, 1) + get_span.assert_called_once_with( + tracer, + None, + properties, + destination=method.exchange, + span_kind=SpanKind.CONSUMER, + task_name=generator_info.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + consume_hook.assert_called_once() + returned_span.end.assert_called_once() + + generator_info.pending_events.reset_mock() + extract.reset_mock() + context_get_current.reset_mock() + get_span.reset_mock() + context_attach.reset_mock() + context_detach.reset_mock() + returned_span.end.reset_mock() + consume_hook.reset_mock() + + # Second call (has detach cleanup) + res = proxy.popleft() + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_called_once_with( + properties.headers, getter=utils._pika_getter + ) + context_get_current.assert_called_once() + self.assertEqual(context_attach.call_count, 2) + self.assertEqual(context_detach.call_count, 2) + get_span.assert_called_once_with( + tracer, + None, + properties, + destination=method.exchange, + span_kind=SpanKind.CONSUMER, + task_name=generator_info.consumer_tag, + operation=MessagingOperationValues.RECEIVE, + ) + consume_hook.assert_called_once() + returned_span.end.assert_called_once() + generator_info.pending_events.reset_mock() + + extract.reset_mock() + context_get_current.reset_mock() + get_span.reset_mock() + context_attach.reset_mock() + context_detach.reset_mock() + returned_span.end.reset_mock() + consume_hook.reset_mock() + + # Third call (cancellation event) + evt = _ConsumerCancellationEvt("") + generator_info.pending_events.popleft.return_value = evt + + res = proxy.popleft() + + self.assertEqual(res, evt) + generator_info.pending_events.popleft.assert_called_once() + extract.assert_not_called() + context_get_current.not_called() + context_detach.assert_called_once() + context_attach.assert_not_called() + get_span.assert_not_called() + consume_hook.assert_not_called() + returned_span.end.assert_not_called() From 7f4853ac798547fd78ead4eaa33fab591996011b Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Mon, 22 Apr 2024 20:23:38 +0200 Subject: [PATCH 12/28] fix: revert modifications to Apache license (#2429) * fix: revert modifications to Apache license See open-telemetry/community#2056 for background * path all LICENSE files Signed-off-by: svrnm * Fix missing LICENSE files --------- Signed-off-by: svrnm Co-authored-by: Diego Hurtado --- LICENSE | 2 +- LICENSE.Apache | 5 +++-- .../opentelemetry-instrumentation-aio-pika/LICENSE | 2 +- .../opentelemetry-instrumentation-aiohttp-client/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-aiopg/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-asgi/LICENSE | 2 +- .../opentelemetry-instrumentation-asyncio/LICENSE | 2 +- .../opentelemetry-instrumentation-asyncpg/LICENSE | 2 +- .../opentelemetry-instrumentation-aws-lambda/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-boto/LICENSE | 2 +- .../opentelemetry-instrumentation-boto3sqs/LICENSE | 2 +- .../opentelemetry-instrumentation-botocore/LICENSE | 2 +- .../opentelemetry-instrumentation-cassandra/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-celery/LICENSE | 2 +- .../opentelemetry-instrumentation-confluent-kafka/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-dbapi/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-django/LICENSE | 2 +- .../opentelemetry-instrumentation-elasticsearch/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-falcon/LICENSE | 2 +- .../opentelemetry-instrumentation-fastapi/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-flask/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-grpc/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-httpx/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-jinja2/LICENSE | 2 +- .../opentelemetry-instrumentation-kafka-python/LICENSE | 2 +- .../opentelemetry-instrumentation-logging/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-mysql/LICENSE | 2 +- .../opentelemetry-instrumentation-mysqlclient/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-pika/LICENSE | 2 +- .../opentelemetry-instrumentation-psycopg/LICENSE | 2 +- .../opentelemetry-instrumentation-psycopg2/LICENSE | 2 +- .../opentelemetry-instrumentation-pymemcache/LICENSE | 2 +- .../opentelemetry-instrumentation-pymongo/LICENSE | 2 +- .../opentelemetry-instrumentation-pymysql/LICENSE | 2 +- .../opentelemetry-instrumentation-pyramid/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-redis/LICENSE | 2 +- .../opentelemetry-instrumentation-remoulade/LICENSE | 2 +- .../opentelemetry-instrumentation-requests/LICENSE | 2 +- .../opentelemetry-instrumentation-sklearn/LICENSE | 2 +- .../opentelemetry-instrumentation-sqlalchemy/LICENSE | 2 +- .../opentelemetry-instrumentation-sqlite3/LICENSE | 2 +- .../opentelemetry-instrumentation-starlette/LICENSE | 2 +- .../opentelemetry-instrumentation-threading/LICENSE | 2 +- .../opentelemetry-instrumentation-tornado/LICENSE | 2 +- .../opentelemetry-instrumentation-tortoiseorm/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-urllib/LICENSE | 2 +- .../opentelemetry-instrumentation-urllib3/LICENSE | 2 +- instrumentation/opentelemetry-instrumentation-wsgi/LICENSE | 2 +- opentelemetry-contrib-instrumentations/LICENSE | 2 +- opentelemetry-instrumentation/LICENSE | 2 +- propagator/opentelemetry-propagator-aws-xray/LICENSE | 2 +- resource/opentelemetry-resource-detector-azure/LICENSE | 2 +- resource/opentelemetry-resource-detector-container/LICENSE | 2 +- sdk-extension/opentelemetry-sdk-extension-aws/LICENSE | 2 +- 54 files changed, 56 insertions(+), 55 deletions(-) diff --git a/LICENSE b/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE.Apache b/LICENSE.Apache index bff56b5431..261eeb9e9f 100644 --- a/LICENSE.Apache +++ b/LICENSE.Apache @@ -178,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +186,8 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016 Datadog, Inc. + Copyright [yyyy] [name of copyright owner] + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE b/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE b/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aiopg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-asgi/LICENSE b/instrumentation/opentelemetry-instrumentation-asgi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asgi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE b/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-boto/LICENSE b/instrumentation/opentelemetry-instrumentation-boto/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-boto/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE b/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-botocore/LICENSE b/instrumentation/opentelemetry-instrumentation-botocore/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-botocore/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE b/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-cassandra/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-celery/LICENSE b/instrumentation/opentelemetry-instrumentation-celery/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-celery/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE b/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-confluent-kafka/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE b/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-dbapi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-django/LICENSE b/instrumentation/opentelemetry-instrumentation-django/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-django/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-django/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE b/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-falcon/LICENSE b/instrumentation/opentelemetry-instrumentation-falcon/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-falcon/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE b/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-fastapi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-flask/LICENSE b/instrumentation/opentelemetry-instrumentation-flask/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-flask/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-grpc/LICENSE b/instrumentation/opentelemetry-instrumentation-grpc/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-grpc/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-httpx/LICENSE b/instrumentation/opentelemetry-instrumentation-httpx/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-httpx/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE b/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-jinja2/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE b/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-kafka-python/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-logging/LICENSE b/instrumentation/opentelemetry-instrumentation-logging/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-logging/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-mysql/LICENSE b/instrumentation/opentelemetry-instrumentation-mysql/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-mysql/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE b/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-mysqlclient/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-pika/LICENSE b/instrumentation/opentelemetry-instrumentation-pika/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pika/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE b/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-psycopg/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE b/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE b/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE b/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymongo/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE b/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pymysql/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE b/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-pyramid/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-redis/LICENSE b/instrumentation/opentelemetry-instrumentation-redis/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-redis/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE b/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-remoulade/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-requests/LICENSE b/instrumentation/opentelemetry-instrumentation-requests/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-requests/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE b/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sklearn/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE b/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE b/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-starlette/LICENSE b/instrumentation/opentelemetry-instrumentation-starlette/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-starlette/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-threading/LICENSE b/instrumentation/opentelemetry-instrumentation-threading/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-threading/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-threading/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-tornado/LICENSE b/instrumentation/opentelemetry-instrumentation-tornado/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-tornado/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE b/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-urllib/LICENSE b/instrumentation/opentelemetry-instrumentation-urllib/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-urllib/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE b/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-urllib3/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE b/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE +++ b/instrumentation/opentelemetry-instrumentation-wsgi/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/opentelemetry-contrib-instrumentations/LICENSE b/opentelemetry-contrib-instrumentations/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/opentelemetry-contrib-instrumentations/LICENSE +++ b/opentelemetry-contrib-instrumentations/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/opentelemetry-instrumentation/LICENSE b/opentelemetry-instrumentation/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/opentelemetry-instrumentation/LICENSE +++ b/opentelemetry-instrumentation/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/propagator/opentelemetry-propagator-aws-xray/LICENSE b/propagator/opentelemetry-propagator-aws-xray/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/propagator/opentelemetry-propagator-aws-xray/LICENSE +++ b/propagator/opentelemetry-propagator-aws-xray/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/resource/opentelemetry-resource-detector-azure/LICENSE b/resource/opentelemetry-resource-detector-azure/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/resource/opentelemetry-resource-detector-azure/LICENSE +++ b/resource/opentelemetry-resource-detector-azure/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/resource/opentelemetry-resource-detector-container/LICENSE b/resource/opentelemetry-resource-detector-container/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/resource/opentelemetry-resource-detector-container/LICENSE +++ b/resource/opentelemetry-resource-detector-container/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE b/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE index 1ef7dad2c5..261eeb9e9f 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE +++ b/sdk-extension/opentelemetry-sdk-extension-aws/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The OpenTelemetry Authors + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 2718ffc7a734bb1f74be5ee89add5ab15bfc29b7 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Mon, 22 Apr 2024 13:48:51 -0500 Subject: [PATCH 13/28] Fix elasticsearch test requirements file name (#2443) Fixes #2442 Co-authored-by: Leighton Chen --- ...{test-requirements-6.txt => test-requirements.txt} | 0 tox.ini | 11 ++++------- 2 files changed, 4 insertions(+), 7 deletions(-) rename instrumentation/opentelemetry-instrumentation-elasticsearch/{test-requirements-6.txt => test-requirements.txt} (100%) diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt similarity index 100% rename from instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt rename to instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt diff --git a/tox.ini b/tox.ini index bee544cb70..e48cc7bfe2 100644 --- a/tox.ini +++ b/tox.ini @@ -76,11 +76,8 @@ envlist = ; opentelemetry-instrumentation-elasticsearch ; FIXME: Elasticsearch >=7 causes CI workflow tests to hang, see open-telemetry/opentelemetry-python-contrib#620 - ; The numbers at the end of the environment names - ; below mean these dependencies are being used: - ; 6: elasticsearch-dsl>=6.0,<7.0 elasticsearch>=6.0,<7.0 - py3{8,9,10,11}-test-instrumentation-elasticsearch-6 - pypy3-test-instrumentation-elasticsearch-6 + py3{8,9,10,11}-test-instrumentation-elasticsearch + pypy3-test-instrumentation-elasticsearch ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 @@ -448,7 +445,7 @@ commands_pre = sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt - elasticsearch-6: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt + elasticsearch: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt asyncio: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt @@ -611,7 +608,7 @@ commands_pre = # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install # for your OS to install the required dependencies pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-6.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt From 4e90498bf394f3c4f6646122cf624304ac8ebc45 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Mon, 22 Apr 2024 15:34:27 -0500 Subject: [PATCH 14/28] Update action versions (#2441) Fixes #2440 Co-authored-by: Leighton Chen --- .github/workflows/backport.yml | 4 ++-- .github/workflows/changelog.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 8 ++++---- .github/workflows/instrumentations_0.yml | 6 +++--- .github/workflows/instrumentations_1.yml | 6 +++--- .github/workflows/prepare-patch-release.yml | 6 +++--- .github/workflows/prepare-release-branch.yml | 12 ++++++------ .github/workflows/publish-a-package-from-tag.yml | 4 ++-- .github/workflows/release.yml | 10 +++++----- .github/workflows/test.yml | 6 +++--- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index f308c5757b..26789093f2 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -16,7 +16,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # history is needed to run git cherry-pick below fetch-depth: 0 @@ -40,4 +40,4 @@ jobs: gh pr create --title "[$GITHUB_REF_NAME] $title" \ --body "Clean cherry-pick of #$NUMBER to the \`$GITHUB_REF_NAME\` branch." \ --head $branch \ - --base $GITHUB_REF_NAME \ No newline at end of file + --base $GITHUB_REF_NAME diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 5238e01c4b..491ddd27fa 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -18,7 +18,7 @@ jobs: && github.actor != 'opentelemetrybot' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check for CHANGELOG changes run: | @@ -33,4 +33,4 @@ jobs: echo "No CHANGELOG was modified." echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." false - fi \ No newline at end of file + fi diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b979a3121b..8ef01d21cb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,16 +20,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: python - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 \ No newline at end of file + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/instrumentations_0.yml b/.github/workflows/instrumentations_0.yml index 256d160640..a138621633 100644 --- a/.github/workflows/instrumentations_0.yml +++ b/.github/workflows/instrumentations_0.yml @@ -104,16 +104,16 @@ jobs: package: "grpc" steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python ${{ env[matrix.python-version] }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ env[matrix.python-version] }} - name: Install tox run: pip install tox - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox diff --git a/.github/workflows/instrumentations_1.yml b/.github/workflows/instrumentations_1.yml index 59db21529a..904f2ee999 100644 --- a/.github/workflows/instrumentations_1.yml +++ b/.github/workflows/instrumentations_1.yml @@ -43,16 +43,16 @@ jobs: package: "prometheus-remote-write" steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python ${{ env[matrix.python-version] }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ env[matrix.python-version] }} - name: Install tox run: pip install tox - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 49b9c89560..7c854d436d 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -6,7 +6,7 @@ jobs: prepare-patch-release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | if [[ ! $GITHUB_REF_NAME =~ ^release/v[0-9]+\.[0-9]+\.x-0\.[0-9]+bx$ ]]; then @@ -50,7 +50,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_VERSION $UNSTABLE_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -79,4 +79,4 @@ jobs: gh pr create --title "[$GITHUB_REF_NAME] $message" \ --body "$message." \ --head $branch \ - --base $GITHUB_REF_NAME \ No newline at end of file + --base $GITHUB_REF_NAME diff --git a/.github/workflows/prepare-release-branch.yml b/.github/workflows/prepare-release-branch.yml index a4caf86ebe..6818772acf 100644 --- a/.github/workflows/prepare-release-branch.yml +++ b/.github/workflows/prepare-release-branch.yml @@ -10,7 +10,7 @@ jobs: prereqs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Verify prerequisites env: @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest needs: prereqs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Create release branch env: @@ -77,7 +77,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_VERSION $UNSTABLE_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -112,7 +112,7 @@ jobs: runs-on: ubuntu-latest needs: prereqs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set environment variables env: @@ -161,7 +161,7 @@ jobs: run: .github/scripts/update-version.sh $STABLE_NEXT_VERSION $UNSTABLE_NEXT_VERSION - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox @@ -192,4 +192,4 @@ jobs: gh pr create --title "$message" \ --body "$body" \ --head $branch \ - --base main \ No newline at end of file + --base main diff --git a/.github/workflows/publish-a-package-from-tag.yml b/.github/workflows/publish-a-package-from-tag.yml index 2c07bf5d7a..a64f5fcf15 100644 --- a/.github/workflows/publish-a-package-from-tag.yml +++ b/.github/workflows/publish-a-package-from-tag.yml @@ -10,8 +10,8 @@ jobs: name: Publish package from tag runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.9' - name: Log tag that triggered publish workflow diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6c267003a..b60ebc7599 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: exit 1 fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set environment variables run: | @@ -56,15 +56,15 @@ jobs: # check out main branch to verify there won't be problems with merging the change log # at the end of this workflow - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: main # back to the release branch - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # next few steps publish to pypi - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v5 with: python-version: '3.8' @@ -127,7 +127,7 @@ jobs: --discussion-category announcements \ v$UNSTABLE_VERSION - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # the step below is creating a pull request against main ref: main diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 10c648e517..529f70e565 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,9 +18,9 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install tox @@ -30,7 +30,7 @@ jobs: run: sudo apt-get install -y libsnappy-dev - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: | .tox From c644f0d7d5f4c8bbb9f89a49f84c0dca2fcc2e7f Mon Sep 17 00:00:00 2001 From: Matt Oberle Date: Mon, 22 Apr 2024 18:44:31 -0400 Subject: [PATCH 15/28] [boto3sqs] Instrument `Session` and `resource` (#2161) * [boto3sqs] Instrument `Session` and `resource` This commit addresses the following open issues: - https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1699 - https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1996 There are four ways to access the SQS API via `boto3`: - `client = boto3.client("sqs")` - `client = boto3.Session().client("sqs")` - `sqs = boto3.resource("sqs")` - `sqs = boto3.Session().resource("sqs")` The existing wrapper tied into `boto3.client` to wrap a generated `botocore.client.SQS` class. The change here covers the three missing initialization methods. * update changelog * rename duplicate test methods * implement uninstrument * [boto3sqs] Reduce number of wrapper targets There are actually 6 ways to initialize a boto3 API object. ```py boto3.client() # Using default global session boto3.resource() # Using default global session boto3.Session().client() # Using "re-exported" session.Session boto3.Session().resource() # Using "re-exported" session.Session boto3.session.Session().client() # Using session.Session directly boto3.session.Session().resource() # Using session.Session directly ``` We only have to patch `session.Session.client` to catch all the cases. - https://github.com/boto/boto3/blob/b3c158c62aa2a1314dc0ec78caea1ea976abd1a0/boto3/session.py#L217-L229 - https://github.com/boto/boto3/blob/b3c158c62aa2a1314dc0ec78caea1ea976abd1a0/boto3/session.py#L446-L457 * Remove unused import --------- Co-authored-by: Matt Oberle Co-authored-by: Diego Hurtado --- CHANGELOG.md | 2 + .../instrumentation/boto3sqs/__init__.py | 6 +- .../tests/test_boto3sqs_instrumentation.py | 74 +++++++++++++++---- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 193779659c..2b2ff4c176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-grpc` AioClientInterceptor should propagate with a Metadata object ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) +- `opentelemetry-instrumentation-boto3sqs` Instrument Session and resource + ([#2161](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2161)) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py index ee7f4a59a6..c0231f81e4 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py @@ -31,7 +31,7 @@ import logging from typing import Any, Collection, Dict, Generator, List, Mapping, Optional -import boto3 +import boto3.session import botocore.client from wrapt import wrap_function_wrapper @@ -382,7 +382,7 @@ def client_wrapper(wrapped, instance, args, kwargs): self._decorate_sqs(type(retval)) return retval - wrap_function_wrapper(boto3, "client", client_wrapper) + wrap_function_wrapper(boto3.session.Session, "client", client_wrapper) def _decorate_sqs(self, sqs_class: type) -> None: """ @@ -433,7 +433,7 @@ def _instrument(self, **kwargs: Dict[str, Any]) -> None: self._decorate_sqs(client_cls) def _uninstrument(self, **kwargs: Dict[str, Any]) -> None: - unwrap(boto3, "client") + unwrap(boto3.session.Session, "client") for client_cls in botocore.client.BaseClient.__subclasses__(): self._un_decorate_sqs(client_cls) diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py index a6ca0e062b..7f7f00cf0a 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/tests/test_boto3sqs_instrumentation.py @@ -20,7 +20,7 @@ import boto3 from botocore.awsrequest import AWSResponse -from wrapt import BoundFunctionWrapper, FunctionWrapper +from wrapt import BoundFunctionWrapper from opentelemetry.instrumentation.boto3sqs import ( Boto3SQSGetter, @@ -37,8 +37,17 @@ from opentelemetry.trace.span import Span, format_span_id, format_trace_id -def _make_sqs_client(): - return boto3.client( +def _make_sqs_client(*, session=False): + return (boto3.Session() if session else boto3).client( + "sqs", + region_name="us-east-1", + aws_access_key_id="dummy", + aws_secret_access_key="dummy", + ) + + +def _make_sqs_resource(*, session=False): + return (boto3.Session() if session else boto3).resource( "sqs", region_name="us-east-1", aws_access_key_id="dummy", @@ -48,7 +57,6 @@ def _make_sqs_client(): class TestBoto3SQSInstrumentor(TestCase): def _assert_instrumented(self, client): - self.assertIsInstance(boto3.client, FunctionWrapper) self.assertIsInstance(client.send_message, BoundFunctionWrapper) self.assertIsInstance(client.send_message_batch, BoundFunctionWrapper) self.assertIsInstance(client.receive_message, BoundFunctionWrapper) @@ -57,6 +65,17 @@ def _assert_instrumented(self, client): client.delete_message_batch, BoundFunctionWrapper ) + def _assert_uninstrumented(self, client): + self.assertNotIsInstance(client.send_message, BoundFunctionWrapper) + self.assertNotIsInstance( + client.send_message_batch, BoundFunctionWrapper + ) + self.assertNotIsInstance(client.receive_message, BoundFunctionWrapper) + self.assertNotIsInstance(client.delete_message, BoundFunctionWrapper) + self.assertNotIsInstance( + client.delete_message_batch, BoundFunctionWrapper + ) + @staticmethod @contextmanager def _active_instrumentor(): @@ -67,19 +86,48 @@ def _active_instrumentor(): Boto3SQSInstrumentor().uninstrument() def test_instrument_api_before_client_init(self) -> None: - with self._active_instrumentor(): - client = _make_sqs_client() - self._assert_instrumented(client) + for session in (False, True): + with self._active_instrumentor(): + client = _make_sqs_client(session=session) + self._assert_instrumented(client) + self._assert_uninstrumented(client) def test_instrument_api_after_client_init(self) -> None: - client = _make_sqs_client() - with self._active_instrumentor(): - self._assert_instrumented(client) + for session in (False, True): + client = _make_sqs_client(session=session) + with self._active_instrumentor(): + self._assert_instrumented(client) + self._assert_uninstrumented(client) def test_instrument_multiple_clients(self): - with self._active_instrumentor(): - self._assert_instrumented(_make_sqs_client()) - self._assert_instrumented(_make_sqs_client()) + for session in (False, True): + with self._active_instrumentor(): + self._assert_instrumented(_make_sqs_client(session=session)) + self._assert_instrumented(_make_sqs_client(session=session)) + + def test_instrument_api_before_resource_init(self) -> None: + for session in (False, True): + with self._active_instrumentor(): + sqs = _make_sqs_resource(session=session) + self._assert_instrumented(sqs.meta.client) + self._assert_uninstrumented(sqs.meta.client) + + def test_instrument_api_after_resource_init(self) -> None: + for session in (False, True): + sqs = _make_sqs_resource(session=session) + with self._active_instrumentor(): + self._assert_instrumented(sqs.meta.client) + self._assert_uninstrumented(sqs.meta.client) + + def test_instrument_multiple_resources(self): + for session in (False, True): + with self._active_instrumentor(): + self._assert_instrumented( + _make_sqs_resource(session=session).meta.client + ) + self._assert_instrumented( + _make_sqs_resource(session=session).meta.client + ) class TestBoto3SQSGetter(TestCase): From 5cb4dab36499985ccf79d30b19dcdfc286d8c261 Mon Sep 17 00:00:00 2001 From: Nick Nicolini <106278816+nicknicolini@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:04:20 -0600 Subject: [PATCH 16/28] Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version (#2404) * Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version The SqlAlchemy commenter is currently using the library version in the comment it emits, e.g.: ``` { 'db_driver': 'psycopg2', 'db_framework': 'sqlalchemy:0.45b0' } ``` We should instead be using the sqlalchemy version here, as SqlCommenter did before * Fix lint * Fix lint * Add CHANGELOG entry --------- Co-authored-by: Diego Hurtado --- CHANGELOG.md | 3 +++ .../src/opentelemetry/instrumentation/sqlalchemy/engine.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2ff4c176..ed7658fe87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version + ([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404)) + ### Added - `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index 0632d71faf..a810aedc38 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -15,13 +15,13 @@ import re import weakref +import sqlalchemy from sqlalchemy.event import ( # pylint: disable=no-name-in-module listen, remove, ) from opentelemetry import trace -from opentelemetry.instrumentation.sqlalchemy.version import __version__ from opentelemetry.instrumentation.sqlcommenter_utils import _add_sql_comment from opentelemetry.instrumentation.utils import _get_opentelemetry_values from opentelemetry.semconv.trace import NetTransportValues, SpanAttributes @@ -227,7 +227,7 @@ def _before_cur_exec( commenter_data = { "db_driver": conn.engine.driver, # Driver/framework centric information. - "db_framework": f"sqlalchemy:{__version__}", + "db_framework": f"sqlalchemy:{sqlalchemy.__version__}", } if self.commenter_options.get("opentelemetry_values", True): From 0980486f2f6bb4cbb3a7711f9530826810a7d27a Mon Sep 17 00:00:00 2001 From: Prakhar Birla Date: Tue, 23 Apr 2024 05:23:59 +0530 Subject: [PATCH 17/28] Fix compatibility issue aio-pika instrumentation (#2450) * - fixed compatibility issue in set_channel of span_builder.py - changed test-requirements-2.txt to use aio-pika==9.0.5 - added test-requirements-3.txt to use aio-pika==9.4.1 (latest atm) - tox.ini: fixed incorrect commands_pre which would always install test-requirements-2.txt and cause dep installation conflict - tox.ini: added aio-pika-3 commands * Add version comment for aio-pika --------- Co-authored-by: Diego Hurtado --- .../instrumentation/aio_pika/span_builder.py | 11 ++++++--- .../test-requirements-2.txt | 6 ++--- .../test-requirements-3.txt | 23 +++++++++++++++++++ tox.ini | 14 +++++------ 4 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py index b73afa62b3..c62b1ea9bf 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/span_builder.py @@ -47,8 +47,13 @@ def set_destination(self, destination: str): self._attributes[SpanAttributes.MESSAGING_DESTINATION] = destination def set_channel(self, channel: AbstractChannel): - connection = channel.connection - if getattr(connection, "connection", None): + if hasattr(channel, "_connection"): + # aio_rmq 9.1 and above removed the connection attribute from the abstract listings + connection = channel._connection + else: + # aio_rmq 9.0.5 and below + connection = channel.connection + if hasattr(connection, "connection"): # aio_rmq 7 url = connection.connection.url else: @@ -57,7 +62,7 @@ def set_channel(self, channel: AbstractChannel): self._attributes.update( { SpanAttributes.NET_PEER_NAME: url.host, - SpanAttributes.NET_PEER_PORT: url.port, + SpanAttributes.NET_PEER_PORT: url.port or 5672, } ) diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt index 3250c93947..7e1aa15fa0 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt @@ -1,5 +1,5 @@ -aio-pika==9.4.0 -aiormq==6.8.0 +aio-pika==9.0.5 +aiormq==6.7.1 asgiref==3.7.2 attrs==23.2.0 Deprecated==1.2.14 @@ -8,7 +8,7 @@ importlib-metadata==6.11.0 iniconfig==2.0.0 multidict==6.0.5 packaging==23.2 -pamqp==3.3.0 +pamqp==3.2.1 pluggy==1.4.0 py==1.11.0 py-cpuinfo==9.0.0 diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt new file mode 100644 index 0000000000..65c2ff8f0c --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt @@ -0,0 +1,23 @@ +aio-pika==9.4.1 +aiormq==6.8.0 +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +idna==3.6 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +multidict==6.0.5 +packaging==23.2 +pamqp==3.3.0 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +tomli==2.0.1 +typing_extensions==4.9.0 +wrapt==1.16.0 +yarl==1.9.4 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-aio-pika diff --git a/tox.ini b/tox.ini index e48cc7bfe2..c9d7772601 100644 --- a/tox.ini +++ b/tox.ini @@ -265,11 +265,12 @@ envlist = ; opentelemetry-instrumentation-aio-pika ; The numbers at the end of the environment names ; below mean these dependencies are being used: - ; 0: aio_pika~=7.2.0 - ; 1: aio_pika>=8.0.0,<9.0.0 - ; 2: aio_pika>=9.0.0,<10.0.0 - py3{8,9,10,11}-test-instrumentation-aio-pika-{0,1,2} - pypy3-test-instrumentation-aio-pika-{0,1,2} + ; 0: aio_pika==7.2.0 + ; 1: aio_pika==8.3.0 + ; 2: aio_pika==9.0.5 + ; 3: aio_pika==9.4.1 + py3{8,9,10,11}-test-instrumentation-aio-pika-{0,1,2,3} + pypy3-test-instrumentation-aio-pika-{0,1,2,3} ; opentelemetry-instrumentation-kafka-python py3{8,9,10,11}-test-instrumentation-kafka-python @@ -338,6 +339,7 @@ commands_pre = aio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-0.txt aio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt aio-pika-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt + aio-pika-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt kafka-python: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt @@ -428,8 +430,6 @@ commands_pre = logging: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt - aio-pika-{0,1,2}: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - aiohttp-client: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt aiohttp-server: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt From 1cd8ccb28a1823ab7dfc81d21c5e5c71f9f0eb7b Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 23 Apr 2024 17:15:22 +0200 Subject: [PATCH 18/28] CHANGELOG: deduplicate unreleased entries (#2451) --- CHANGELOG.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed7658fe87..4cbc913346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version - ([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404)) - -### Added - -- `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported - only for global, non channel specific instrumentation) - ([#2397](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2397))) - - ### Breaking changes - Rename `type` attribute to `asgi.event.type` in `opentelemetry-instrumentation-asgi` @@ -35,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) - `opentelemetry-instrumentation-threading` Initial release for threading ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) +- `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported + only for global, non channel specific instrumentation) + ([#2397](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2397))) ### Fixed @@ -42,15 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) - `opentelemetry-instrumentation-boto3sqs` Instrument Session and resource ([#2161](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2161)) - -### Added - -- `opentelemetry-sdk-extension-aws` Register AWS resource detectors under the `opentelemetry_resource_detector` entry point - ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) -- `opentelemetry-instrumentation-wsgi` Implement new semantic convention opt-in with stable http semantic conventions - ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) -- `opentelemetry-instrumentation-threading` Initial release for threading - ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) +- Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version + ([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404)) ## Version 1.24.0/0.45b0 (2024-03-28) From a0c3211c4fd3326279740480c0c1938a17a125c8 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 23 Apr 2024 17:45:48 +0200 Subject: [PATCH 19/28] Bump black to 24.3.0 (#2452) --- .flake8 | 4 +++ dev-requirements.txt | 2 +- .../prometheus_remote_write/gen/remote_pb2.py | 12 +++---- .../prometheus_remote_write/gen/types_pb2.py | 36 +++++++++---------- .../instrumentation/asgi/__init__.py | 6 ++-- .../instrumentation/asyncpg/__init__.py | 12 +++---- .../botocore/extensions/lmbd.py | 6 ++-- .../botocore/extensions/sns.py | 6 ++-- .../botocore/extensions/sqs.py | 6 ++-- .../django/middleware/otel_middleware.py | 18 +++++----- .../middleware/sqlcommenter_middleware.py | 24 ++++++++----- .../tests/test_middleware.py | 8 +++-- .../tests/views.py | 12 +++---- .../instrumentation/elasticsearch/__init__.py | 6 ++-- .../instrumentation/falcon/__init__.py | 6 ++-- .../instrumentation/flask/__init__.py | 12 +++---- .../tests/base_test.py | 18 +++++----- .../tests/protobuf/test_server_pb2.py | 4 +-- .../instrumentation/httpx/__init__.py | 4 +-- .../instrumentation/pika/pika_instrumentor.py | 6 ++-- .../instrumentation/pika/utils.py | 17 ++++----- .../instrumentation/pymemcache/__init__.py | 12 +++---- .../instrumentation/pymongo/__init__.py | 3 +- .../instrumentation/pyramid/callbacks.py | 12 +++---- .../instrumentation/redis/util.py | 12 +++---- .../instrumentation/requests/__init__.py | 20 ++++++----- .../instrumentation/sqlalchemy/engine.py | 12 +++---- .../system_metrics/__init__.py | 20 ++++++----- .../instrumentation/tornado/__init__.py | 6 ++-- .../instrumentation/tortoiseorm/__init__.py | 18 +++++----- .../instrumentation/urllib/__init__.py | 14 ++++---- .../instrumentation/urllib3/__init__.py | 8 +++-- .../tests/test_wsgi_middleware.py | 18 +++++----- .../opentelemetry/instrumentation/_semconv.py | 12 +++---- .../propagators/ot_trace/__init__.py | 6 ++-- .../resource/detector/azure/app_service.py | 20 +++++------ scripts/check_for_valid_readme.py | 1 + 37 files changed, 219 insertions(+), 200 deletions(-) diff --git a/.flake8 b/.flake8 index 8b2144c00f..5683cfc1f3 100644 --- a/.flake8 +++ b/.flake8 @@ -12,6 +12,10 @@ ignore = # allow whitespace before ':' (https://github.com/psf/black#slices) E203 + # conflicts with black + E701 + E704 + exclude = .bzr .git diff --git a/dev-requirements.txt b/dev-requirements.txt index fffb4c445d..1c49c57b7e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,7 +1,7 @@ pylint==3.0.2 flake8==6.1.0 isort==5.12.0 -black==22.3.0 +black==24.3.0 httpretty==1.1.4 mypy==0.931 sphinx==7.1.2 diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py index 3efcb36536..f8724074f6 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/remote_pb2.py @@ -34,13 +34,13 @@ DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b"Z\006prompb" _WRITEREQUEST.fields_by_name["timeseries"]._options = None - _WRITEREQUEST.fields_by_name[ - "timeseries" - ]._serialized_options = b"\310\336\037\000" + _WRITEREQUEST.fields_by_name["timeseries"]._serialized_options = ( + b"\310\336\037\000" + ) _WRITEREQUEST.fields_by_name["metadata"]._options = None - _WRITEREQUEST.fields_by_name[ - "metadata" - ]._serialized_options = b"\310\336\037\000" + _WRITEREQUEST.fields_by_name["metadata"]._serialized_options = ( + b"\310\336\037\000" + ) _WRITEREQUEST._serialized_start = 216 _WRITEREQUEST._serialized_end = 338 _READREQUEST._serialized_start = 341 diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py index fbfa2123ad..30cf2e38cc 100644 --- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py +++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/gen/types_pb2.py @@ -31,31 +31,31 @@ DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b"Z\006prompb" _EXEMPLAR.fields_by_name["labels"]._options = None - _EXEMPLAR.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _EXEMPLAR.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["labels"]._options = None - _TIMESERIES.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["samples"]._options = None - _TIMESERIES.fields_by_name[ - "samples" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["samples"]._serialized_options = ( + b"\310\336\037\000" + ) _TIMESERIES.fields_by_name["exemplars"]._options = None - _TIMESERIES.fields_by_name[ - "exemplars" - ]._serialized_options = b"\310\336\037\000" + _TIMESERIES.fields_by_name["exemplars"]._serialized_options = ( + b"\310\336\037\000" + ) _LABELS.fields_by_name["labels"]._options = None _LABELS.fields_by_name["labels"]._serialized_options = b"\310\336\037\000" _CHUNKEDSERIES.fields_by_name["labels"]._options = None - _CHUNKEDSERIES.fields_by_name[ - "labels" - ]._serialized_options = b"\310\336\037\000" + _CHUNKEDSERIES.fields_by_name["labels"]._serialized_options = ( + b"\310\336\037\000" + ) _CHUNKEDSERIES.fields_by_name["chunks"]._options = None - _CHUNKEDSERIES.fields_by_name[ - "chunks" - ]._serialized_options = b"\310\336\037\000" + _CHUNKEDSERIES.fields_by_name["chunks"]._serialized_options = ( + b"\310\336\037\000" + ) _METRICMETADATA._serialized_start = 152 _METRICMETADATA._serialized_end = 400 _METRICMETADATA_METRICTYPE._serialized_start = 279 diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py index 8e4d699cbb..405c470ceb 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -695,9 +695,9 @@ async def otel_send(message: dict[str, Any]): if send_span.is_recording(): if message["type"] == "http.response.start": status_code = message["status"] - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = status_code + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + status_code + ) set_status_code(server_span, status_code) set_status_code(send_span, status_code) diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py index 11c579f96a..798a5dc00b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py @@ -77,14 +77,14 @@ def _hydrate_span_from_args(connection, query, parameters) -> dict: if isinstance(addr, tuple): span_attributes[SpanAttributes.NET_PEER_NAME] = addr[0] span_attributes[SpanAttributes.NET_PEER_PORT] = addr[1] - span_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + span_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) elif isinstance(addr, str): span_attributes[SpanAttributes.NET_PEER_NAME] = addr - span_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + span_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) if query is not None: span_attributes[SpanAttributes.DB_STATEMENT] = query diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py index 299a37ab6c..57fb8b6794 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py @@ -62,9 +62,9 @@ def extract_attributes( cls, call_context: _AwsSdkCallContext, attributes: _AttributeMapT ): attributes[SpanAttributes.FAAS_INVOKED_PROVIDER] = "aws" - attributes[ - SpanAttributes.FAAS_INVOKED_NAME - ] = cls._parse_function_name(call_context) + attributes[SpanAttributes.FAAS_INVOKED_NAME] = ( + cls._parse_function_name(call_context) + ) attributes[SpanAttributes.FAAS_INVOKED_REGION] = call_context.region @classmethod diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py index aa55ae697f..9c3df3a2bc 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sns.py @@ -76,9 +76,9 @@ def extract_attributes( destination_name, is_phone_number = cls._extract_destination_name( call_context ) - attributes[ - SpanAttributes.MESSAGING_DESTINATION_KIND - ] = MessagingDestinationKindValues.TOPIC.value + attributes[SpanAttributes.MESSAGING_DESTINATION_KIND] = ( + MessagingDestinationKindValues.TOPIC.value + ) attributes[SpanAttributes.MESSAGING_DESTINATION] = destination_name # TODO: Use SpanAttributes.MESSAGING_DESTINATION_NAME when opentelemetry-semantic-conventions 0.42b0 is released diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py index 777108cbb5..194e47b57f 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/sqs.py @@ -35,9 +35,9 @@ def extract_attributes(self, attributes: _AttributeMapT): attributes[SpanAttributes.MESSAGING_SYSTEM] = "aws.sqs" attributes[SpanAttributes.MESSAGING_URL] = queue_url try: - attributes[ - SpanAttributes.MESSAGING_DESTINATION - ] = queue_url.split("/")[-1] + attributes[SpanAttributes.MESSAGING_DESTINATION] = ( + queue_url.split("/")[-1] + ) except IndexError: _logger.error( "Could not extract messaging destination from '%s'", diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py index bc677a81cf..1b747fd2c0 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/otel_middleware.py @@ -163,9 +163,9 @@ class _DjangoMiddleware(MiddlewareMixin): _active_request_counter = None _otel_request_hook: Callable[[Span, HttpRequest], None] = None - _otel_response_hook: Callable[ - [Span, HttpRequest, HttpResponse], None - ] = None + _otel_response_hook: Callable[[Span, HttpRequest, HttpResponse], None] = ( + None + ) @staticmethod def _get_span_name(request): @@ -229,9 +229,9 @@ def process_request(self, request): ) duration_attrs = _parse_duration_attrs(attributes) - request.META[ - self._environ_active_request_attr_key - ] = active_requests_count_attrs + request.META[self._environ_active_request_attr_key] = ( + active_requests_count_attrs + ) request.META[self._environ_duration_attr_key] = duration_attrs self._active_request_counter.add(1, active_requests_count_attrs) if span.is_recording(): @@ -336,9 +336,9 @@ def process_response(self, request, response): self._environ_duration_attr_key, None ) if duration_attrs: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = response.status_code + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + response.status_code + ) request_start_time = request.META.pop(self._environ_timer_key, None) if activation and span: diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py index 30492a8be5..ef53d5dc38 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py @@ -83,20 +83,26 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T: sql = _add_sql_comment( sql, # Information about the controller. - controller=resolver_match.view_name - if resolver_match and with_controller - else None, + controller=( + resolver_match.view_name + if resolver_match and with_controller + else None + ), # route is the pattern that matched a request with a controller i.e. the regex # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.route # getattr() because the attribute doesn't exist in Django < 2.2. - route=getattr(resolver_match, "route", None) - if resolver_match and with_route - else None, + route=( + getattr(resolver_match, "route", None) + if resolver_match and with_route + else None + ), # app_name is the application namespace for the URL pattern that matches the URL. # See https://docs.djangoproject.com/en/stable/ref/urlresolvers/#django.urls.ResolverMatch.app_name - app_name=(resolver_match.app_name or None) - if resolver_match and with_app_name - else None, + app_name=( + (resolver_match.app_name or None) + if resolver_match and with_app_name + else None + ), # Framework centric information. framework=f"django:{_django_version}" if with_framework else None, # Information about the database and driver. diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 4d221fae62..63af1e6b86 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -155,9 +155,11 @@ def test_templated_route_get(self): self.assertEqual( span.name, - "GET ^route/(?P[0-9]{4})/template/$" - if DJANGO_2_2 - else "GET", + ( + "GET ^route/(?P[0-9]{4})/template/$" + if DJANGO_2_2 + else "GET" + ), ) self.assertEqual(span.kind, SpanKind.SERVER) self.assertEqual(span.status.status_code, StatusCode.UNSET) diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/views.py b/instrumentation/opentelemetry-instrumentation-django/tests/views.py index 452a7c0fdd..6310664100 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/views.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/views.py @@ -35,12 +35,12 @@ def response_with_custom_header(request): response = HttpResponse() response["custom-test-header-1"] = "test-header-value-1" response["custom-test-header-2"] = "test-header-value-2" - response[ - "my-custom-regex-header-1" - ] = "my-custom-regex-value-1,my-custom-regex-value-2" - response[ - "my-custom-regex-header-2" - ] = "my-custom-regex-value-3,my-custom-regex-value-4" + response["my-custom-regex-header-1"] = ( + "my-custom-regex-value-1,my-custom-regex-value-2" + ) + response["my-custom-regex-header-2"] = ( + "my-custom-regex-value-3,my-custom-regex-value-4" + ) response["my-secret-header"] = "my-secret-value" return response diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py index 0f5056de83..ceb50cac56 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py @@ -247,9 +247,9 @@ def wrapper(wrapped, _, args, kwargs): if body: # Don't set db.statement for bulk requests, as it can be very large if isinstance(body, dict): - attributes[ - SpanAttributes.DB_STATEMENT - ] = sanitize_body(body) + attributes[SpanAttributes.DB_STATEMENT] = ( + sanitize_body(body) + ) if params: attributes["elasticsearch.params"] = str(params) if doc_id: diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 06a550cf3f..79c9a0cf0f 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -382,9 +382,9 @@ def _start_response(status, response_headers, *args, **kwargs): raise finally: if span.is_recording(): - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) + ) duration = max(round((default_timer() - start) * 1000), 0) self.duration_histogram.record(duration, duration_attrs) self.active_requests_counter.add(-1, active_requests_count_attrs) diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index ba1031655e..a17f83a877 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -334,9 +334,9 @@ def _start_response(status, response_headers, *args, **kwargs): ) status_code = otel_wsgi._parse_status_code(status) if status_code is not None: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = status_code + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + status_code + ) if ( span.is_recording() and span.kind == trace.SpanKind.SERVER @@ -641,9 +641,9 @@ def instrument_app( tracer, excluded_urls=excluded_urls, enable_commenter=enable_commenter, - commenter_options=commenter_options - if commenter_options - else {}, + commenter_options=( + commenter_options if commenter_options else {} + ), ) app._before_request = _before_request app.before_request(_before_request) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py index 3c8073f261..307ac3ccf0 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py @@ -76,15 +76,15 @@ def _custom_response_headers(): resp = flask.Response("test response") resp.headers["content-type"] = "text/plain; charset=utf-8" resp.headers["content-length"] = "13" - resp.headers[ - "my-custom-header" - ] = "my-custom-value-1,my-custom-header-2" - resp.headers[ - "my-custom-regex-header-1" - ] = "my-custom-regex-value-1,my-custom-regex-value-2" - resp.headers[ - "My-Custom-Regex-Header-2" - ] = "my-custom-regex-value-3,my-custom-regex-value-4" + resp.headers["my-custom-header"] = ( + "my-custom-value-1,my-custom-header-2" + ) + resp.headers["my-custom-regex-header-1"] = ( + "my-custom-regex-value-1,my-custom-regex-value-2" + ) + resp.headers["My-Custom-Regex-Header-2"] = ( + "my-custom-regex-value-3,my-custom-regex-value-4" + ) resp.headers["my-secret-header"] = "my-secret-value" return resp diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py index ad3dcf3fe7..f00b5f82e7 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/protobuf/test_server_pb2.py @@ -142,7 +142,7 @@ (_message.Message,), { "DESCRIPTOR": _REQUEST, - "__module__": "test_server_pb2" + "__module__": "test_server_pb2", # @@protoc_insertion_point(class_scope:Request) }, ) @@ -153,7 +153,7 @@ (_message.Message,), { "DESCRIPTOR": _RESPONSE, - "__module__": "test_server_pb2" + "__module__": "test_server_pb2", # @@protoc_insertion_point(class_scope:Response) }, ) diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py index e6609157c4..7fcc7128be 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -433,9 +433,7 @@ async def __aexit__( ) -> None: await self._transport.__aexit__(exc_type, exc_value, traceback) - async def handle_async_request( - self, *args, **kwargs - ) -> typing.Union[ + async def handle_async_request(self, *args, **kwargs) -> typing.Union[ typing.Tuple[int, "Headers", httpx.AsyncByteStream, dict], httpx.Response, ]: diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py index 76261c89ce..f37f74e396 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/pika_instrumentor.py @@ -156,9 +156,9 @@ def uninstrument_channel(channel: BlockingChannel) -> None: callback_attr = PikaInstrumentor.CONSUMER_CALLBACK_ATTR consumer_callback = getattr(client_info, callback_attr, None) if hasattr(consumer_callback, "_original_callback"): - channel._consumer_infos[ - consumers_tag - ] = consumer_callback._original_callback + channel._consumer_infos[consumers_tag] = ( + consumer_callback._original_callback + ) PikaInstrumentor._uninstrument_channel_functions(channel) def _decorate_channel_function( diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py index 5afa5d9ee6..2b4d1204ea 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/utils.py @@ -38,8 +38,7 @@ def keys(self, carrier: CarrierT) -> List[str]: HookT = Callable[[Span, bytes, BasicProperties], None] -def dummy_callback(span: Span, body: bytes, properties: BasicProperties): - ... +def dummy_callback(span: Span, body: bytes, properties: BasicProperties): ... def _decorate_callback( @@ -66,9 +65,9 @@ def decorated_callback( tracer, channel, properties, - destination=method.exchange - if method.exchange - else method.routing_key, + destination=( + method.exchange if method.exchange else method.routing_key + ), span_kind=SpanKind.CONSUMER, task_name=task_name, operation=MessagingOperationValues.RECEIVE, @@ -243,9 +242,11 @@ def popleft(self, *args, **kwargs): self._self_tracer, None, properties, - destination=method.exchange - if method.exchange - else method.routing_key, + destination=( + method.exchange + if method.exchange + else method.routing_key + ), span_kind=SpanKind.CONSUMER, task_name=self._self_queue_consumer_generator.consumer_tag, operation=MessagingOperationValues.RECEIVE, diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py index 512ce9ea56..d763734aca 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py @@ -162,14 +162,14 @@ def _get_address_attributes(instance): host, port = instance.server address_attributes[SpanAttributes.NET_PEER_NAME] = host address_attributes[SpanAttributes.NET_PEER_PORT] = port - address_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + address_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) elif isinstance(instance.server, str): address_attributes[SpanAttributes.NET_PEER_NAME] = instance.server - address_attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + address_attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) return address_attributes diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py index 506669a5c6..f55aa2be33 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py @@ -98,8 +98,7 @@ def failed_hook(span, event): FailedHookT = Callable[[Span, monitoring.CommandFailedEvent], None] -def dummy_callback(span, event): - ... +def dummy_callback(span, event): ... class CommandTracer(monitoring.CommandListener): diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py index 4f17da3da5..ede3e09608 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -106,9 +106,9 @@ def _before_traversal(event): if span.is_recording(): attributes = otel_wsgi.collect_request_attributes(request_environ) if request.matched_route: - attributes[ - SpanAttributes.HTTP_ROUTE - ] = request.matched_route.pattern + attributes[SpanAttributes.HTTP_ROUTE] = ( + request.matched_route.pattern + ) for key, value in attributes.items(): span.set_attribute(key, value) if span.kind == trace.SpanKind.SERVER: @@ -201,9 +201,9 @@ def trace_tween(request): status = getattr(response, "status", status) status_code = otel_wsgi._parse_status_code(status) if status_code is not None: - duration_attrs[ - SpanAttributes.HTTP_STATUS_CODE - ] = otel_wsgi._parse_status_code(status) + duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( + otel_wsgi._parse_status_code(status) + ) duration_histogram.record(duration, duration_attrs) active_requests_counter.add(-1, active_requests_count_attrs) span = request.environ.get(_ENVIRON_SPAN_KEY) diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py index 3c274c8c43..2a24ead79a 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py @@ -36,14 +36,14 @@ def _extract_conn_attributes(conn_kwargs): attributes[SpanAttributes.NET_PEER_PORT] = conn_kwargs.get( "port", 6379 ) - attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) except KeyError: attributes[SpanAttributes.NET_PEER_NAME] = conn_kwargs.get("path", "") - attributes[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + attributes[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) return attributes diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index 2052fe47cd..f468ff87ff 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -189,9 +189,9 @@ def get_or_create_headers(): sem_conv_opt_in_mode, ) # Use semconv library when available - span_attributes[ - _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS - ] = parsed_url.hostname + span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS] = ( + parsed_url.hostname + ) if parsed_url.port: _set_http_peer_port_client( metric_labels, parsed_url.port, sem_conv_opt_in_mode @@ -201,9 +201,9 @@ def get_or_create_headers(): span_attributes, parsed_url.port, sem_conv_opt_in_mode ) # Use semconv library when available - span_attributes[ - _SPAN_ATTRIBUTES_NETWORK_PEER_PORT - ] = parsed_url.port + span_attributes[_SPAN_ATTRIBUTES_NETWORK_PEER_PORT] = ( + parsed_url.port + ) except ValueError: pass @@ -413,9 +413,11 @@ def _instrument(self, **kwargs): duration_histogram_new, request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), sem_conv_opt_in_mode=semconv_opt_in_mode, ) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index a810aedc38..172c1193f3 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -296,18 +296,18 @@ def _get_attributes_from_cursor(vendor, cursor, attrs): is_unix_socket = info.host and info.host.startswith("/") if is_unix_socket: - attrs[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.OTHER.value + attrs[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.OTHER.value + ) if info.port: # postgresql enforces this pattern on all socket names attrs[SpanAttributes.NET_PEER_NAME] = os.path.join( info.host, f".s.PGSQL.{info.port}" ) else: - attrs[ - SpanAttributes.NET_TRANSPORT - ] = NetTransportValues.IP_TCP.value + attrs[SpanAttributes.NET_TRANSPORT] = ( + NetTransportValues.IP_TCP.value + ) attrs[SpanAttributes.NET_PEER_NAME] = info.host if info.port: attrs[SpanAttributes.NET_PEER_PORT] = int(info.port) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 32766fa0c5..74d4f6a431 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -481,9 +481,11 @@ def _get_system_swap_utilization( if hasattr(system_swap, metric): self._system_swap_utilization_labels["state"] = metric yield Observation( - getattr(system_swap, metric) / system_swap.total - if system_swap.total - else 0, + ( + getattr(system_swap, metric) / system_swap.total + if system_swap.total + else 0 + ), self._system_swap_utilization_labels.copy(), ) @@ -556,9 +558,9 @@ def _get_system_network_dropped_packets( for metric in self._config["system.network.dropped.packets"]: in_out = {"receive": "in", "transmit": "out"}[metric] if hasattr(counters, f"drop{in_out}"): - self._system_network_dropped_packets_labels[ - "device" - ] = device + self._system_network_dropped_packets_labels["device"] = ( + device + ) self._system_network_dropped_packets_labels[ "direction" ] = metric @@ -629,9 +631,9 @@ def _get_system_network_connections( 1: "tcp", 2: "udp", }[net_connection.type.value] - self._system_network_connections_labels[ - "state" - ] = net_connection.status + self._system_network_connections_labels["state"] = ( + net_connection.status + ) self._system_network_connections_labels[metric] = getattr( net_connection, metric ) diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index 5a39538837..5c99457a39 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -455,9 +455,9 @@ def _get_attributes_from_request(request): if hasattr(request.connection, "context") and getattr( request.connection.context, "_orig_remote_ip", None ): - attrs[ - SpanAttributes.NET_PEER_IP - ] = request.connection.context._orig_remote_ip + attrs[SpanAttributes.NET_PEER_IP] = ( + request.connection.context._orig_remote_ip + ) return extract_attributes_from_object( request, _traced_request_attrs, attrs diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py index 7988daf130..cebcb81ced 100644 --- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py @@ -229,17 +229,17 @@ def _hydrate_span_from_args(self, connection, query, parameters) -> dict: capabilities = getattr(connection, "capabilities", None) if capabilities is not None: if capabilities.dialect == "sqlite": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.SQLITE.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.SQLITE.value + ) elif capabilities.dialect == "postgres": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.POSTGRESQL.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.POSTGRESQL.value + ) elif capabilities.dialect == "mysql": - span_attributes[ - SpanAttributes.DB_SYSTEM - ] = DbSystemValues.MYSQL.value + span_attributes[SpanAttributes.DB_SYSTEM] = ( + DbSystemValues.MYSQL.value + ) dbname = getattr(connection, "filename", None) if dbname: span_attributes[SpanAttributes.DB_NAME] = dbname diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py index 3738c4d2c6..befc022b35 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -156,9 +156,11 @@ def _instrument(self, **kwargs): histograms, request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), ) def _uninstrument(self, **kwargs): @@ -251,9 +253,9 @@ def _instrumented_open_call( ver_ = str(getattr(result, "version", "")) if ver_: - labels[ - SpanAttributes.HTTP_FLAVOR - ] = f"{ver_[:1]}.{ver_[:-1]}" + labels[SpanAttributes.HTTP_FLAVOR] = ( + f"{ver_[:1]}.{ver_[:-1]}" + ) _record_histograms( histograms, labels, request, result, elapsed_time diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index 985f291199..add5db8f19 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -200,9 +200,11 @@ def _instrument(self, **kwargs): request_hook=kwargs.get("request_hook"), response_hook=kwargs.get("response_hook"), url_filter=kwargs.get("url_filter"), - excluded_urls=_excluded_urls_from_env - if excluded_urls is None - else parse_excluded_urls(excluded_urls), + excluded_urls=( + _excluded_urls_from_env + if excluded_urls is None + else parse_excluded_urls(excluded_urls) + ), ) def _uninstrument(self, **kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index 985fbe0571..b55ac6808f 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -252,9 +252,9 @@ def validate_response( if old_sem_conv: expected_attributes[SpanAttributes.HTTP_METHOD] = http_method if new_sem_conv: - expected_attributes[ - SpanAttributes.HTTP_REQUEST_METHOD - ] = http_method + expected_attributes[SpanAttributes.HTTP_REQUEST_METHOD] = ( + http_method + ) self.assertEqual(span_list[0].attributes, expected_attributes) def test_basic_wsgi_call(self): @@ -562,9 +562,9 @@ def validate_url( parts.path, 1 )[1] if parts.query: - expected_new[ - SpanAttributes.URL_QUERY - ] = expected_url.split(parts.query, 1)[1] + expected_new[SpanAttributes.URL_QUERY] = ( + expected_url.split(parts.query, 1)[1] + ) else: expected_new[SpanAttributes.HTTP_URL] = expected_url if has_host: @@ -710,9 +710,9 @@ def test_request_attributes_pathless(self): def test_request_attributes_with_full_request_uri(self): self.environ["HTTP_HOST"] = "127.0.0.1:8080" self.environ["REQUEST_METHOD"] = "CONNECT" - self.environ[ - "REQUEST_URI" - ] = "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing" # Might happen in a CONNECT request + self.environ["REQUEST_URI"] = ( + "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing" # Might happen in a CONNECT request + ) expected_old = { SpanAttributes.HTTP_HOST: "127.0.0.1:8080", SpanAttributes.HTTP_TARGET: "http://docs.python.org:80/3/library/urllib.parse.html?highlight=params#url-parsing", diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index 31c2486acc..8f236b5479 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -368,16 +368,16 @@ def _set_status( span.set_attribute( SpanAttributes.HTTP_RESPONSE_STATUS_CODE, status_code ) - metrics_attributes[ - SpanAttributes.HTTP_RESPONSE_STATUS_CODE - ] = status_code + metrics_attributes[SpanAttributes.HTTP_RESPONSE_STATUS_CODE] = ( + status_code + ) if status == StatusCode.ERROR: span.set_attribute( _SPAN_ATTRIBUTES_ERROR_TYPE, status_code_str ) - metrics_attributes[ - _SPAN_ATTRIBUTES_ERROR_TYPE - ] = status_code_str + metrics_attributes[_SPAN_ATTRIBUTES_ERROR_TYPE] = ( + status_code_str + ) span.set_status(Status(status)) diff --git a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py index c5c3496248..7924fe0b57 100644 --- a/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py +++ b/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry/propagators/ot_trace/__init__.py @@ -98,9 +98,9 @@ def extract( if not key.startswith(OT_BAGGAGE_PREFIX): continue - baggage[ - key[len(OT_BAGGAGE_PREFIX) :] - ] = _extract_first_element(getter.get(carrier, key)) + baggage[key[len(OT_BAGGAGE_PREFIX) :]] = ( + _extract_first_element(getter.get(carrier, key)) + ) for key, value in baggage.items(): context = set_baggage(key, value, context) diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py index 1e853acc57..b4daa4cc84 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py @@ -47,19 +47,19 @@ def detect(self) -> Resource: website_site_name = environ.get(_WEBSITE_SITE_NAME) if website_site_name: attributes[ResourceAttributes.SERVICE_NAME] = website_site_name - attributes[ - ResourceAttributes.CLOUD_PROVIDER - ] = CloudProviderValues.AZURE.value - attributes[ - ResourceAttributes.CLOUD_PLATFORM - ] = CloudPlatformValues.AZURE_APP_SERVICE.value + attributes[ResourceAttributes.CLOUD_PROVIDER] = ( + CloudProviderValues.AZURE.value + ) + attributes[ResourceAttributes.CLOUD_PLATFORM] = ( + CloudPlatformValues.AZURE_APP_SERVICE.value + ) azure_resource_uri = _get_azure_resource_uri(website_site_name) if azure_resource_uri: - attributes[ - ResourceAttributes.CLOUD_RESOURCE_ID - ] = azure_resource_uri - for (key, env_var) in _APP_SERVICE_ATTRIBUTE_ENV_VARS.items(): + attributes[ResourceAttributes.CLOUD_RESOURCE_ID] = ( + azure_resource_uri + ) + for key, env_var in _APP_SERVICE_ATTRIBUTE_ENV_VARS.items(): value = environ.get(env_var) if value: attributes[key] = value diff --git a/scripts/check_for_valid_readme.py b/scripts/check_for_valid_readme.py index 42446dd741..11b1fa81ac 100644 --- a/scripts/check_for_valid_readme.py +++ b/scripts/check_for_valid_readme.py @@ -1,4 +1,5 @@ """Test script to check given paths for valid README.rst files.""" + import argparse import sys from pathlib import Path From 5375acf534f70f827d108ce2f2e7b8d728b2fc8e Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Thu, 25 Apr 2024 08:25:34 -0700 Subject: [PATCH 20/28] new(opentelemetry-processor-baggage): add new component (#2436) * new(opentelemetry-processor-baggage): add new component Fixes #2428 Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * add tests Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * update changelog Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * update component owners Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * lint Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * update license Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * fix lint Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * lint Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> * rename processors dir to processor Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --------- Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- .github/component_owners.yml | 3 + CHANGELOG.md | 2 + .../opentelemetry-processor-baggage/LICENSE | 201 ++++++++++++++++++ .../README.rst | 22 ++ .../pyproject.toml | 44 ++++ .../processor/baggage/__init__.py | 20 ++ .../processor/baggage/processor.py | 55 +++++ .../processor/baggage/version.py | 15 ++ .../test-requirements.txt | 2 + .../tests/__init__.py | 13 ++ .../tests/test_baggage_processor.py | 89 ++++++++ tox.ini | 8 + 12 files changed, 474 insertions(+) create mode 100644 processor/opentelemetry-processor-baggage/LICENSE create mode 100644 processor/opentelemetry-processor-baggage/README.rst create mode 100644 processor/opentelemetry-processor-baggage/pyproject.toml create mode 100644 processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py create mode 100644 processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py create mode 100644 processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py create mode 100644 processor/opentelemetry-processor-baggage/test-requirements.txt create mode 100644 processor/opentelemetry-processor-baggage/tests/__init__.py create mode 100644 processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py diff --git a/.github/component_owners.yml b/.github/component_owners.yml index ab14a41aec..efd15a6775 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -73,3 +73,6 @@ components: instrumentation/opentelemetry-instrumentation-psycopg: - federicobond + + processor/opentelemetry-processor-baggage: + - codeboten diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cbc913346..7d2a3e8314 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported only for global, non channel specific instrumentation) ([#2397](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2397))) +- `opentelemetry-processor-baggage` Initial release + ([#2436](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2436)) ### Fixed diff --git a/processor/opentelemetry-processor-baggage/LICENSE b/processor/opentelemetry-processor-baggage/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/processor/opentelemetry-processor-baggage/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/processor/opentelemetry-processor-baggage/README.rst b/processor/opentelemetry-processor-baggage/README.rst new file mode 100644 index 0000000000..2768758a99 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/README.rst @@ -0,0 +1,22 @@ +OpenTelemetry Baggage Span Processor +==================================== + +The BaggageSpanProcessor reads entries stored in Baggage +from the parent context and adds the baggage entries' keys and +values to the span as attributes on span start. + +Add this span processor to a tracer provider. + +Keys and values added to Baggage will appear on subsequent child +spans for a trace within this service *and* be propagated to external +services in accordance with any configured propagation formats +configured. If the external services also have a Baggage span +processor, the keys and values will appear in those child spans as +well. + +⚠ Warning ⚠️ + +Do not put sensitive information in Baggage. + +To repeat: a consequence of adding data to Baggage is that the keys and +values will appear in all outgoing HTTP headers from the application. diff --git a/processor/opentelemetry-processor-baggage/pyproject.toml b/processor/opentelemetry-processor-baggage/pyproject.toml new file mode 100644 index 0000000000..0ef5392fdb --- /dev/null +++ b/processor/opentelemetry-processor-baggage/pyproject.toml @@ -0,0 +1,44 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-processor-baggage" +dynamic = ["version"] +description = "OpenTelemetry Baggage Span Processor" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.8" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "opentelemetry-api ~= 1.5", + "wrapt >= 1.0.0, < 2.0.0", +] + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/processor/opentelemetry-processor-baggage" + +[tool.hatch.version] +path = "src/opentelemetry/processor/baggage/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py new file mode 100644 index 0000000000..a740c66491 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/__init__.py @@ -0,0 +1,20 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=import-error + +from .processor import BaggageSpanProcessor +from .version import __version__ + +__all__ = ["BaggageSpanProcessor", "__version__"] diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py new file mode 100644 index 0000000000..36df06a94c --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py @@ -0,0 +1,55 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + +from opentelemetry.baggage import get_all as get_all_baggage +from opentelemetry.context import Context +from opentelemetry.sdk.trace.export import SpanProcessor +from opentelemetry.trace import Span + + +class BaggageSpanProcessor(SpanProcessor): + """ + The BaggageSpanProcessor reads entries stored in Baggage + from the parent context and adds the baggage entries' keys and + values to the span as attributes on span start. + + Add this span processor to a tracer provider. + + Keys and values added to Baggage will appear on subsequent child + spans for a trace within this service *and* be propagated to external + services in accordance with any configured propagation formats + configured. If the external services also have a Baggage span + processor, the keys and values will appear in those child spans as + well. + + ⚠ Warning ⚠️ + + Do not put sensitive information in Baggage. + + To repeat: a consequence of adding data to Baggage is that the keys and + values will appear in all outgoing HTTP headers from the application. + + """ + + def __init__(self) -> None: + pass + + def on_start( + self, span: "Span", parent_context: Optional[Context] = None + ) -> None: + baggage = get_all_baggage(parent_context) + for key, value in baggage.items(): + span.set_attribute(key, value) diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py new file mode 100644 index 0000000000..ff4933b20b --- /dev/null +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/version.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__version__ = "0.46b0.dev" diff --git a/processor/opentelemetry-processor-baggage/test-requirements.txt b/processor/opentelemetry-processor-baggage/test-requirements.txt new file mode 100644 index 0000000000..fa7ad3d793 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/test-requirements.txt @@ -0,0 +1,2 @@ + +-e processor/opentelemetry-processor-baggage \ No newline at end of file diff --git a/processor/opentelemetry-processor-baggage/tests/__init__.py b/processor/opentelemetry-processor-baggage/tests/__init__.py new file mode 100644 index 0000000000..b0a6f42841 --- /dev/null +++ b/processor/opentelemetry-processor-baggage/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py b/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py new file mode 100644 index 0000000000..63a71c3cba --- /dev/null +++ b/processor/opentelemetry-processor-baggage/tests/test_baggage_processor.py @@ -0,0 +1,89 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from opentelemetry.baggage import get_all as get_all_baggage +from opentelemetry.baggage import set_baggage +from opentelemetry.context import attach, detach +from opentelemetry.processor.baggage import BaggageSpanProcessor +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import SpanProcessor +from opentelemetry.trace import Span, Tracer + + +class BaggageSpanProcessorTest(unittest.TestCase): + def test_check_the_baggage(self): + self.assertIsInstance(BaggageSpanProcessor(), SpanProcessor) + + def test_set_baggage_attaches_to_child_spans_and_detaches_properly_with_context( + self, + ): + tracer_provider = TracerProvider() + tracer_provider.add_span_processor(BaggageSpanProcessor()) + + # tracer has no baggage to start + tracer = tracer_provider.get_tracer("my-tracer") + self.assertIsInstance(tracer, Tracer) + self.assertEqual(get_all_baggage(), {}) + # set baggage in context + ctx = set_baggage("queen", "bee") + with tracer.start_as_current_span( + name="bumble", context=ctx + ) as bumble_span: + # span should have baggage key-value pair in context + self.assertEqual(get_all_baggage(ctx), {"queen": "bee"}) + # span should have baggage key-value pair in attribute + self.assertEqual(bumble_span._attributes["queen"], "bee") + with tracer.start_as_current_span( + name="child_span", context=ctx + ) as child_span: + self.assertIsInstance(child_span, Span) + # child span should have baggage key-value pair in context + self.assertEqual(get_all_baggage(ctx), {"queen": "bee"}) + # child span should have baggage key-value pair in attribute + self.assertEqual(child_span._attributes["queen"], "bee") + + def test_set_baggage_attaches_to_child_spans_and_detaches_properly_with_token( + self, + ): + tracer_provider = TracerProvider() + tracer_provider.add_span_processor(BaggageSpanProcessor()) + + # tracer has no baggage to start + tracer = tracer_provider.get_tracer("my-tracer") + self.assertIsInstance(tracer, Tracer) + self.assertEqual(get_all_baggage(), {}) + # create a context token and set baggage + honey_token = attach(set_baggage("bumble", "bee")) + self.assertEqual(get_all_baggage(), {"bumble": "bee"}) + # in a new span, ensure the baggage is there + with tracer.start_as_current_span("parent") as span: + self.assertEqual(get_all_baggage(), {"bumble": "bee"}) + self.assertEqual(span._attributes["bumble"], "bee") + # create a second context token and set more baggage + moar_token = attach(set_baggage("moar", "bee")) + self.assertEqual( + get_all_baggage(), {"bumble": "bee", "moar": "bee"} + ) + # in a child span, ensure all baggage is there as attributes + with tracer.start_as_current_span("child") as child_span: + self.assertEqual( + get_all_baggage(), {"bumble": "bee", "moar": "bee"} + ) + self.assertEqual(child_span._attributes["bumble"], "bee") + self.assertEqual(child_span._attributes["moar"], "bee") + detach(moar_token) + detach(honey_token) + self.assertEqual(get_all_baggage(), {}) diff --git a/tox.ini b/tox.ini index c9d7772601..0fb11855e8 100644 --- a/tox.ini +++ b/tox.ini @@ -287,6 +287,10 @@ envlist = py3{8,9,10,11}-test-instrumentation-cassandra pypy3-test-instrumentation-cassandra + ; opentelemetry-processor-baggage + py3{8,9,10,11}-test-processor-baggage + pypy3-test-processor-baggage + lint spellcheck docker-tests @@ -466,6 +470,8 @@ commands_pre = propagator-aws-xray: pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt + processor-baggage: pip install -r {toxinidir}/processor/opentelemetry-processor-baggage/test-requirements.txt + ; we have to install packages in editable mode. coverage: python {toxinidir}/scripts/eachdist.py install --editable @@ -523,6 +529,7 @@ commands = test-util-http: pytest {toxinidir}/util/opentelemetry-util-http/tests {posargs} test-sdk-extension-aws: pytest {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests {posargs} test-resource-detector-container: pytest {toxinidir}/resource/opentelemetry-resource-detector-container/tests {posargs} + test-processor-baggage: pytest {toxinidir}/processor/opentelemetry-processor-baggage/tests {posargs} test-propagator-aws: pytest {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests {posargs} test-propagator-ot-trace: pytest {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests {posargs} test-exporter-richconsole: pytest {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests {posargs} @@ -622,6 +629,7 @@ commands_pre = pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt # requires snappy headers to be available on the system pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/test-requirements.txt + pip install -r {toxinidir}/processor/opentelemetry-processor-baggage/test-requirements.txt pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt From d5b5925cf8506a6f099394d1fbcfbe8e6ceaa8fe Mon Sep 17 00:00:00 2001 From: Alessandro Bologna Date: Thu, 25 Apr 2024 11:57:39 -0400 Subject: [PATCH 21/28] Fix exception handling for events with requestContext (#2418) * Fix exception handling for events with requestContext * added entry to changelog * reformatted with black --------- Co-authored-by: Diego Hurtado --- CHANGELOG.md | 2 ++ .../instrumentation/aws_lambda/__init__.py | 1 + .../test_aws_lambda_instrumentation_manual.py | 25 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d2a3e8314..3bcc845bcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2363](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2363)) - `opentelemetry-instrumentation-boto3sqs` Instrument Session and resource ([#2161](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2161)) +- `opentelemetry-instrumentation-aws-lambda` Fix exception handling for events with requestContext + ([#2418](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2418)) - Use sqlalchemy version in sqlalchemy commenter instead of opentelemetry library version ([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404)) 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 8f29a0ec38..7614ba9813 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -365,6 +365,7 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches ) exception = None + result = None try: result = call_wrapped(*args, **kwargs) except Exception as exc: # pylint: disable=W0703 diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py index 51ebb67ebc..a2730028e8 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py @@ -436,6 +436,31 @@ def test_lambda_handles_handler_exception(self): exc_env_patch.stop() + def test_lambda_handles_handler_exception_with_api_gateway_proxy_event( + self, + ): + exc_env_patch = mock.patch.dict( + "os.environ", + {_HANDLER: "tests.mocks.lambda_function.handler_exc"}, + ) + exc_env_patch.start() + AwsLambdaInstrumentor().instrument() + # instrumentor re-raises the exception + with self.assertRaises(Exception): + mock_execute_lambda( + {"requestContext": {"http": {"method": "GET"}}} + ) + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + span = spans[0] + self.assertEqual(span.status.status_code, StatusCode.ERROR) + self.assertEqual(len(span.events), 1) + event = span.events[0] + self.assertEqual(event.name, "exception") + + exc_env_patch.stop() + def test_uninstrument(self): AwsLambdaInstrumentor().instrument() From c8d5f851ed212b2464594fa53ca28a803beff8f4 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Thu, 25 Apr 2024 10:40:03 -0700 Subject: [PATCH 22/28] HTTP transition for flask (#2454) --- CHANGELOG.md | 6 + instrumentation/README.md | 4 +- .../instrumentation/flask/__init__.py | 141 +++++++-- .../instrumentation/flask/package.py | 2 + .../tests/test_copy_context.py | 2 +- .../tests/test_programmatic.py | 290 ++++++++++++++++-- .../instrumentation/requests/__init__.py | 8 +- .../instrumentation/wsgi/package.py | 2 + .../tests/test_wsgi_middleware.py | 2 + .../opentelemetry/instrumentation/_semconv.py | 8 +- 10 files changed, 399 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bcc845bcc..ceb97433f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2372](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2372)) - Drop support for instrumenting elasticsearch client < 6` ([#2422](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2422)) +- `opentelemetry-instrumentation-wsgi` Add `http.method` to `span.name` + ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) +- `opentelemetry-instrumentation-flask` Add `http.method` to `span.name` + ([#2454](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2454)) ### Added @@ -23,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#2382](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2382)) - `opentelemetry-instrumentation-wsgi` Implement new semantic convention opt-in with stable http semantic conventions ([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425)) +- `opentelemetry-instrumentation-flask` Implement new semantic convention opt-in with stable http semantic conventions + ([#2454](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2454)) - `opentelemetry-instrumentation-threading` Initial release for threading ([#2253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2253)) - `opentelemetry-instrumentation-pika` Instrumentation for `channel.consume()` (supported diff --git a/instrumentation/README.md b/instrumentation/README.md index 284037d707..c73d0f7c0a 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -20,7 +20,7 @@ | [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 2.0 | No | experimental | [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 4.0.0 | Yes | experimental | [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | experimental -| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | experimental +| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | migration | [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio ~= 1.27 | No | experimental | [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No | experimental | [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No | experimental @@ -48,4 +48,4 @@ | [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No | experimental | [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes | experimental | [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes | experimental -| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes | experimental \ No newline at end of file +| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes | migration \ No newline at end of file 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 a17f83a877..f2e0ee34cc 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -250,6 +250,15 @@ def response_hook(span: Span, status: str, response_headers: List): import opentelemetry.instrumentation.wsgi as otel_wsgi from opentelemetry import context, trace +from opentelemetry.instrumentation._semconv import ( + _METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + _get_schema_url, + _HTTPStabilityMode, + _OpenTelemetrySemanticConventionStability, + _OpenTelemetryStabilitySignalType, + _report_new, + _report_old, +) from opentelemetry.instrumentation.flask.package import _instruments from opentelemetry.instrumentation.flask.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -260,7 +269,11 @@ def response_hook(span: Span, status: str, response_headers: List): from opentelemetry.metrics import get_meter from opentelemetry.semconv.metrics import MetricInstruments from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.util.http import get_excluded_urls, parse_excluded_urls +from opentelemetry.util.http import ( + get_excluded_urls, + parse_excluded_urls, + sanitize_method, +) _logger = getLogger(__name__) @@ -286,8 +299,13 @@ def _request_ctx_ref() -> weakref.ReferenceType: def get_default_span_name(): + method = sanitize_method( + flask.request.environ.get("REQUEST_METHOD", "").strip() + ) + if method == "_OTHER": + method = "HTTP" try: - span_name = flask.request.url_rule.rule + span_name = f"{method} {flask.request.url_rule.rule}" except AttributeError: span_name = otel_wsgi.get_default_span_name(flask.request.environ) return span_name @@ -296,9 +314,11 @@ def get_default_span_name(): def _rewrapped_app( wsgi_app, active_requests_counter, - duration_histogram, + duration_histogram_old=None, response_hook=None, excluded_urls=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, + duration_histogram_new=None, ): def _wrapped_app(wrapped_app_environ, start_response): # We want to measure the time for route matching, etc. @@ -307,11 +327,16 @@ def _wrapped_app(wrapped_app_environ, start_response): # we better avoid it. wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = time_ns() start = default_timer() - attributes = otel_wsgi.collect_request_attributes(wrapped_app_environ) + attributes = otel_wsgi.collect_request_attributes( + wrapped_app_environ, sem_conv_opt_in_mode + ) active_requests_count_attrs = ( - otel_wsgi._parse_active_request_count_attrs(attributes) + otel_wsgi._parse_active_request_count_attrs( + attributes, + sem_conv_opt_in_mode, + ) ) - duration_attrs = otel_wsgi._parse_duration_attrs(attributes) + active_requests_counter.add(1, active_requests_count_attrs) def _start_response(status, response_headers, *args, **kwargs): @@ -330,13 +355,12 @@ def _start_response(status, response_headers, *args, **kwargs): if span: otel_wsgi.add_response_attributes( - span, status, response_headers + span, + status, + response_headers, + attributes, + sem_conv_opt_in_mode, ) - status_code = otel_wsgi._parse_status_code(status) - if status_code is not None: - duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = ( - status_code - ) if ( span.is_recording() and span.kind == trace.SpanKind.SERVER @@ -357,8 +381,21 @@ def _start_response(status, response_headers, *args, **kwargs): return start_response(status, response_headers, *args, **kwargs) result = wsgi_app(wrapped_app_environ, _start_response) - duration = max(round((default_timer() - start) * 1000), 0) - duration_histogram.record(duration, duration_attrs) + duration_s = default_timer() - start + if duration_histogram_old: + duration_attrs_old = otel_wsgi._parse_duration_attrs( + attributes, _HTTPStabilityMode.DEFAULT + ) + duration_histogram_old.record( + max(round(duration_s * 1000), 0), duration_attrs_old + ) + if duration_histogram_new: + duration_attrs_new = otel_wsgi._parse_duration_attrs( + attributes, _HTTPStabilityMode.HTTP + ) + duration_histogram_new.record( + max(duration_s, 0), duration_attrs_new + ) active_requests_counter.add(-1, active_requests_count_attrs) return result @@ -371,6 +408,7 @@ def _wrapped_before_request( excluded_urls=None, enable_commenter=True, commenter_options=None, + sem_conv_opt_in_mode=_HTTPStabilityMode.DEFAULT, ): def _before_request(): if excluded_urls and excluded_urls.url_disabled(flask.request.url): @@ -379,7 +417,8 @@ def _before_request(): span_name = get_default_span_name() attributes = otel_wsgi.collect_request_attributes( - flask_request_environ + flask_request_environ, + sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) if flask.request.url_rule: # For 404 that result from no route found, etc, we @@ -490,6 +529,7 @@ class _InstrumentedFlask(flask.Flask): _enable_commenter = True _commenter_options = None _meter_provider = None + _sem_conv_opt_in_mode = _HTTPStabilityMode.DEFAULT def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -503,11 +543,20 @@ def __init__(self, *args, **kwargs): _InstrumentedFlask._meter_provider, schema_url="https://opentelemetry.io/schemas/1.11.0", ) - duration_histogram = meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", - ) + duration_histogram_old = None + if _report_old(_InstrumentedFlask._sem_conv_opt_in_mode): + duration_histogram_old = meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + duration_histogram_new = None + if _report_new(_InstrumentedFlask._sem_conv_opt_in_mode): + duration_histogram_new = meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, unit="requests", @@ -517,9 +566,11 @@ def __init__(self, *args, **kwargs): self.wsgi_app = _rewrapped_app( self.wsgi_app, active_requests_counter, - duration_histogram, + duration_histogram_old, _InstrumentedFlask._response_hook, excluded_urls=_InstrumentedFlask._excluded_urls, + sem_conv_opt_in_mode=_InstrumentedFlask._sem_conv_opt_in_mode, + duration_histogram_new=duration_histogram_new, ) tracer = trace.get_tracer( @@ -535,6 +586,7 @@ def __init__(self, *args, **kwargs): excluded_urls=_InstrumentedFlask._excluded_urls, enable_commenter=_InstrumentedFlask._enable_commenter, commenter_options=_InstrumentedFlask._commenter_options, + sem_conv_opt_in_mode=_InstrumentedFlask._sem_conv_opt_in_mode, ) self._before_request = _before_request self.before_request(_before_request) @@ -578,11 +630,19 @@ def _instrument(self, **kwargs): _InstrumentedFlask._commenter_options = commenter_options meter_provider = kwargs.get("meter_provider") _InstrumentedFlask._meter_provider = meter_provider + + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) + + _InstrumentedFlask._sem_conv_opt_in_mode = sem_conv_opt_in_mode + flask.Flask = _InstrumentedFlask def _uninstrument(self, **kwargs): flask.Flask = self._original_flask + # pylint: disable=too-many-locals @staticmethod def instrument_app( app, @@ -598,6 +658,11 @@ def instrument_app( app._is_instrumented_by_opentelemetry = False if not app._is_instrumented_by_opentelemetry: + # initialize semantic conventions opt-in if needed + _OpenTelemetrySemanticConventionStability._initialize() + sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode( + _OpenTelemetryStabilitySignalType.HTTP, + ) excluded_urls = ( parse_excluded_urls(excluded_urls) if excluded_urls is not None @@ -607,33 +672,44 @@ def instrument_app( __name__, __version__, meter_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", - ) - duration_histogram = meter.create_histogram( - name=MetricInstruments.HTTP_SERVER_DURATION, - unit="ms", - description="Duration of HTTP client requests.", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) + duration_histogram_old = None + if _report_old(sem_conv_opt_in_mode): + duration_histogram_old = meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + description="measures the duration of the inbound HTTP request", + ) + duration_histogram_new = None + if _report_new(sem_conv_opt_in_mode): + duration_histogram_new = meter.create_histogram( + name=_METRIC_ATTRIBUTES_SERVER_DURATION_NAME, + unit="s", + description="measures the duration of the inbound HTTP request", + ) active_requests_counter = meter.create_up_down_counter( name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, - unit="requests", - description="measures the number of concurrent HTTP requests that are currently in-flight", + unit="{request}", + description="Number of active HTTP server requests.", ) app._original_wsgi_app = app.wsgi_app app.wsgi_app = _rewrapped_app( app.wsgi_app, active_requests_counter, - duration_histogram, - response_hook, + duration_histogram_old, + response_hook=response_hook, excluded_urls=excluded_urls, + sem_conv_opt_in_mode=sem_conv_opt_in_mode, + duration_histogram_new=duration_histogram_new, ) tracer = trace.get_tracer( __name__, __version__, tracer_provider, - schema_url="https://opentelemetry.io/schemas/1.11.0", + schema_url=_get_schema_url(sem_conv_opt_in_mode), ) _before_request = _wrapped_before_request( @@ -644,6 +720,7 @@ def instrument_app( commenter_options=( commenter_options if commenter_options else {} ), + sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) app._before_request = _before_request app.before_request(_before_request) diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py index d83adbede0..150ca0ca9e 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/package.py @@ -16,3 +16,5 @@ _instruments = ("flask >= 1.0",) _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py index 96268de5e7..7a57d01c43 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_copy_context.py @@ -44,5 +44,5 @@ def test_copycontext(self): resp = client.get("/copy_context", headers={"x-req": "a-header"}) self.assertEqual(200, resp.status_code) - self.assertEqual("/copy_context", resp.json["span_name"]) + self.assertEqual("GET /copy_context", resp.json["span_name"]) self.assertEqual("a-header", resp.json["request_header"]) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index 82ca88460c..d30a100b0e 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. +# pylint: disable=too-many-lines from timeit import default_timer from unittest.mock import Mock, patch @@ -19,7 +20,12 @@ from opentelemetry import trace from opentelemetry.instrumentation._semconv import ( + _SPAN_ATTRIBUTES_ERROR_TYPE, + OTEL_SEMCONV_STABILITY_OPT_IN, + _OpenTelemetrySemanticConventionStability, + _server_active_requests_count_attrs_new, _server_active_requests_count_attrs_old, + _server_duration_attrs_new, _server_duration_attrs_old, ) from opentelemetry.instrumentation.flask import FlaskInstrumentor @@ -65,26 +71,71 @@ def expected_attributes(override_attributes): return default_attributes -_expected_metric_names = [ +def expected_attributes_new(override_attributes): + default_attributes = { + SpanAttributes.HTTP_REQUEST_METHOD: "GET", + SpanAttributes.SERVER_PORT: 80, + SpanAttributes.SERVER_ADDRESS: "localhost", + SpanAttributes.URL_PATH: "/hello/123", + SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.1", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200, + } + for key, val in override_attributes.items(): + default_attributes[key] = val + return default_attributes + + +_expected_metric_names_old = [ "http.server.active_requests", "http.server.duration", ] -_recommended_attrs = { +_expected_metric_names_new = [ + "http.server.active_requests", + "http.server.request.duration", +] +_recommended_metrics_attrs_old = { "http.server.active_requests": _server_active_requests_count_attrs_old, "http.server.duration": _server_duration_attrs_old, } +_recommended_metrics_attrs_new = { + "http.server.active_requests": _server_active_requests_count_attrs_new, + "http.server.request.duration": _server_duration_attrs_new, +} +_server_active_requests_count_attrs_both = ( + _server_active_requests_count_attrs_old +) +_server_active_requests_count_attrs_both.extend( + _server_active_requests_count_attrs_new +) +_recommended_metrics_attrs_both = { + "http.server.active_requests": _server_active_requests_count_attrs_both, + "http.server.duration": _server_duration_attrs_old, + "http.server.request.duration": _server_duration_attrs_new, +} +# pylint: disable=too-many-public-methods class TestProgrammatic(InstrumentationTest, WsgiTestBase): def setUp(self): super().setUp() + test_name = "" + if hasattr(self, "_testMethodName"): + test_name = self._testMethodName + sem_conv_mode = "default" + if "new_semconv" in test_name: + sem_conv_mode = "http" + elif "both_semconv" in test_name: + sem_conv_mode = "http/dup" + self.env_patch = patch.dict( "os.environ", { - "OTEL_PYTHON_FLASK_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg" + "OTEL_PYTHON_FLASK_EXCLUDED_URLS": "http://localhost/env_excluded_arg/123,env_excluded_noarg", + OTEL_SEMCONV_STABILITY_OPT_IN: sem_conv_mode, }, ) + _OpenTelemetrySemanticConventionStability._initialized = False self.env_patch.start() self.exclude_patch = patch( @@ -170,7 +221,45 @@ def test_simple(self): span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "/hello/") + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_simple_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.URL_SCHEME: "http", + } + ) + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_simple_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_TARGET: "/hello/123", + SpanAttributes.HTTP_ROUTE: "/hello/", + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) @@ -220,6 +309,53 @@ def test_404(self): self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) + def test_404_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.HTTP_REQUEST_METHOD: "POST", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 404, + SpanAttributes.URL_PATH: "/bye", + SpanAttributes.URL_SCHEME: "http", + } + ) + + resp = self.client.post("/bye") + self.assertEqual(404, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "POST /bye") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_404_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_METHOD: "POST", + SpanAttributes.HTTP_TARGET: "/bye", + SpanAttributes.HTTP_STATUS_CODE: 404, + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.HTTP_REQUEST_METHOD: "POST", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 404, + SpanAttributes.URL_PATH: "/bye", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + + resp = self.client.post("/bye") + self.assertEqual(404, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "POST /bye") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + def test_internal_error(self): expected_attrs = expected_attributes( { @@ -233,7 +369,53 @@ def test_internal_error(self): resp.close() span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "/hello/") + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_internal_error_new_semconv(self): + expected_attrs = expected_attributes_new( + { + SpanAttributes.URL_PATH: "/hello/500", + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500, + _SPAN_ATTRIBUTES_ERROR_TYPE: "500", + SpanAttributes.URL_SCHEME: "http", + } + ) + resp = self.client.get("/hello/500") + self.assertEqual(500, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_internal_error_both_semconv(self): + expected_attrs = expected_attributes( + { + SpanAttributes.HTTP_TARGET: "/hello/500", + SpanAttributes.HTTP_ROUTE: "/hello/", + SpanAttributes.HTTP_STATUS_CODE: 500, + } + ) + expected_attrs.update( + expected_attributes_new( + { + SpanAttributes.URL_PATH: "/hello/500", + SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 500, + _SPAN_ATTRIBUTES_ERROR_TYPE: "500", + SpanAttributes.URL_SCHEME: "http", + } + ) + ) + resp = self.client.get("/hello/500") + self.assertEqual(500, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "GET /hello/") self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) @@ -291,7 +473,7 @@ def test_flask_metrics(self): for scope_metric in resource_metric.scope_metrics: self.assertTrue(len(scope_metric.metrics) != 0) for metric in scope_metric.metrics: - self.assertIn(metric.name, _expected_metric_names) + self.assertIn(metric.name, _expected_metric_names_old) data_points = list(metric.data.data_points) self.assertEqual(len(data_points), 1) for point in data_points: @@ -305,7 +487,42 @@ def test_flask_metrics(self): number_data_point_seen = True for attr in point.attributes: self.assertIn( - attr, _recommended_attrs[metric.name] + attr, + _recommended_metrics_attrs_old[metric.name], + ) + self.assertTrue(number_data_point_seen and histogram_data_point_seen) + + def test_flask_metrics_new_semconv(self): + start = default_timer() + self.client.get("/hello/123") + self.client.get("/hello/321") + self.client.get("/hello/756") + duration = max(round((default_timer() - start) * 1000), 0) + metrics_list = self.memory_metrics_reader.get_metrics_data() + number_data_point_seen = False + histogram_data_point_seen = False + self.assertTrue(len(metrics_list.resource_metrics) != 0) + for resource_metric in metrics_list.resource_metrics: + self.assertTrue(len(resource_metric.scope_metrics) != 0) + for scope_metric in resource_metric.scope_metrics: + self.assertTrue(len(scope_metric.metrics) != 0) + for metric in scope_metric.metrics: + self.assertIn(metric.name, _expected_metric_names_new) + data_points = list(metric.data.data_points) + self.assertEqual(len(data_points), 1) + for point in data_points: + if isinstance(point, HistogramDataPoint): + self.assertEqual(point.count, 3) + self.assertAlmostEqual( + duration, point.sum, delta=10 + ) + histogram_data_point_seen = True + if isinstance(point, NumberDataPoint): + number_data_point_seen = True + for attr in point.attributes: + self.assertIn( + attr, + _recommended_metrics_attrs_new[metric.name], ) self.assertTrue(number_data_point_seen and histogram_data_point_seen) @@ -375,6 +592,23 @@ def test_basic_metric_success(self): expected_requests_count_attributes, ) + def test_basic_metric_success_new_semconv(self): + self.client.get("/hello/756") + expected_duration_attributes = { + "http.request.method": "GET", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 200, + } + expected_requests_count_attributes = { + "http.request.method": "GET", + "url.scheme": "http", + } + self._assert_basic_metric( + expected_duration_attributes, + expected_requests_count_attributes, + ) + def test_basic_metric_nonstandard_http_method_success(self): self.client.open("/hello/756", method="NONSTANDARD") expected_duration_attributes = { @@ -401,32 +635,42 @@ def test_basic_metric_nonstandard_http_method_success(self): expected_requests_count_attributes, ) + def test_basic_metric_nonstandard_http_method_success_new_semconv(self): + self.client.open("/hello/756", method="NONSTANDARD") + expected_duration_attributes = { + "http.request.method": "_OTHER", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 405, + } + expected_requests_count_attributes = { + "http.request.method": "_OTHER", + "url.scheme": "http", + } + self._assert_basic_metric( + expected_duration_attributes, + expected_requests_count_attributes, + ) + @patch.dict( "os.environ", { OTEL_PYTHON_INSTRUMENTATION_HTTP_CAPTURE_ALL_METHODS: "1", }, ) - def test_basic_metric_nonstandard_http_method_allowed_success(self): + def test_basic_metric_nonstandard_http_method_allowed_success_new_semconv( + self, + ): self.client.open("/hello/756", method="NONSTANDARD") expected_duration_attributes = { - "http.method": "NONSTANDARD", - "http.host": "localhost", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "localhost", - "net.host.port": 80, - "http.status_code": 405, - "net.host.name": "localhost", + "http.request.method": "NONSTANDARD", + "url.scheme": "http", + "network.protocol.version": "1.1", + "http.response.status_code": 405, } expected_requests_count_attributes = { - "http.method": "NONSTANDARD", - "http.host": "localhost", - "http.scheme": "http", - "http.flavor": "1.1", - "http.server_name": "localhost", - "net.host.name": "localhost", - "net.host.port": 80, + "http.request.method": "NONSTANDARD", + "url.scheme": "http", } self._assert_basic_metric( expected_duration_attributes, diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index f468ff87ff..12797d6f5e 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -172,9 +172,11 @@ def get_or_create_headers(): try: parsed_url = urlparse(url) if parsed_url.scheme: - _set_http_scheme( - metric_labels, parsed_url.scheme, sem_conv_opt_in_mode - ) + if _report_old(sem_conv_opt_in_mode): + # TODO: Support opt-in for url.scheme in new semconv + _set_http_scheme( + metric_labels, parsed_url.scheme, sem_conv_opt_in_mode + ) if parsed_url.hostname: _set_http_host( metric_labels, parsed_url.hostname, sem_conv_opt_in_mode diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py index 942f175da1..1bb8350a06 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/package.py @@ -16,3 +16,5 @@ _instruments = tuple() _supports_metrics = True + +_semconv_status = "migration" diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index b55ac6808f..2b26cbb5f9 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -241,6 +241,7 @@ def validate_response( SpanAttributes.SERVER_ADDRESS: "127.0.0.1", SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", SpanAttributes.HTTP_RESPONSE_STATUS_CODE: 200, + SpanAttributes.URL_SCHEME: "http", } if old_sem_conv: expected_attributes.update(expected_attributes_old) @@ -522,6 +523,7 @@ def test_request_attributes_new_semconv(self): SpanAttributes.NETWORK_PROTOCOL_VERSION: "1.0", SpanAttributes.URL_PATH: "/", SpanAttributes.URL_QUERY: "foo=bar", + SpanAttributes.URL_SCHEME: "http", }, ) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index 8f236b5479..efe3c75f70 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -65,8 +65,7 @@ SpanAttributes.HTTP_RESPONSE_STATUS_CODE, SpanAttributes.HTTP_ROUTE, SpanAttributes.NETWORK_PROTOCOL_VERSION, - # TODO: Support opt-in for scheme in new semconv - # SpanAttributes.URL_SCHEME, + SpanAttributes.URL_SCHEME, ] _server_active_requests_count_attrs_old = [ @@ -234,9 +233,8 @@ def _set_http_url(result, url, sem_conv_opt_in_mode): def _set_http_scheme(result, scheme, sem_conv_opt_in_mode): if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_SCHEME, scheme) - # TODO: Support opt-in for scheme in new semconv - # if _report_new(sem_conv_opt_in_mode): - # set_string_attribute(result, SpanAttributes.URL_SCHEME, scheme) + if _report_new(sem_conv_opt_in_mode): + set_string_attribute(result, SpanAttributes.URL_SCHEME, scheme) def _set_http_host(result, host, sem_conv_opt_in_mode): From bd4a22a0d92a33bb27034e1993d78707f75a4dfb Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Apr 2024 16:23:22 -0500 Subject: [PATCH 23/28] Remove unnecessary package installations (#2424) * Remove unnecessary dependency installations Fixes #2423 * Fix tox.ini merge conflicts --- tox.ini | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 231 insertions(+), 16 deletions(-) diff --git a/tox.ini b/tox.ini index 0fb11855e8..783f66e064 100644 --- a/tox.ini +++ b/tox.ini @@ -239,6 +239,10 @@ envlist = pypy3-test-instrumentation-tortoiseorm ; opentelemetry-instrumentation-httpx + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: httpx>=0.18.0,<0.19.0 respx~=0.17.0 + ; 1: httpx>=0.19.0 respx~=0.20.1 py3{8,9,10,11}-test-instrumentation-httpx-{0,1} pypy3-test-instrumentation-httpx-{0,1} @@ -317,69 +321,144 @@ setenv = CORE_REPO=git+https://github.com/open-telemetry/opentelemetry-python.git@{env:CORE_REPO_SHA} commands_pre = -; Install without -e to test the actual installation - py3{8,9,10,11}: python -m pip install -U pip setuptools wheel -; Install common packages for all the tests. These are not needed in all the -; cases but it saves a lot of boilerplate in this file. - test: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api - test: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions - test: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk - test: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils - test: pip install {toxinidir}/opentelemetry-instrumentation - + opentelemetry-instrumentation: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + opentelemetry-instrumentation: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + opentelemetry-instrumentation: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + opentelemetry-instrumentation: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils opentelemetry-instrumentation: pip install -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt + distro: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + distro: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + distro: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + distro: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils distro: pip install -r {toxinidir}/opentelemetry-distro/test-requirements.txt + asgi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asgi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asgi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asgi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils asgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt + celery: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + celery: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + celery: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + celery: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils py3{8,9}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt py3{10,11}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt pypy3-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + sio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sio-pika: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk sio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt sio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt + aio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aio-pika: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk aio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-0.txt aio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt aio-pika-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt aio-pika-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt + kafka-python: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + kafka-python: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + kafka-python: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk kafka-python: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt + confluent-kafka: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + confluent-kafka: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + confluent-kafka: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + confluent-kafka: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils confluent-kafka: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt + grpc: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + grpc: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + grpc: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + grpc: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils grpc: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt + wsgi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + wsgi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + wsgi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + wsgi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils wsgi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt + asyncpg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asyncpg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asyncpg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asyncpg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils asyncpg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt + aws-lambda: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aws-lambda: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aws-lambda: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aws-lambda: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aws-lambda: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt + boto: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + boto: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + boto: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + boto: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils boto: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt + boto3sqs: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + boto3sqs: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + boto3sqs: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + boto3sqs: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils boto3sqs: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt + falcon: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + falcon: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + falcon: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + falcon: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils falcon-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-0.txt falcon-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt falcon-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt + flask: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + flask: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + flask: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + flask: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils flask-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-0.txt flask-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt flask-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt + urllib: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + urllib: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + urllib: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + urllib: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils urllib: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt + urllib3: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + urllib3: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + urllib3: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + urllib3: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils urllib3-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-0.txt urllib3-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt + botocore: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + botocore: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + botocore: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + botocore: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils botocore: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt + cassandra: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + cassandra: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + cassandra: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + cassandra: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils cassandra: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt + dbapi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + dbapi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + dbapi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + dbapi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils dbapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt + django: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + django: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + django: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + django: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils py3{8,9}-test-instrumentation-django-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt py3{8,9}-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt py3{8,9}-test-instrumentation-django-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-2.txt @@ -388,90 +467,226 @@ commands_pre = pypy3-test-instrumentation-django-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt pypy3-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt + fastapi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + fastapi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + fastapi: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + fastapi: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils fastapi: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt + mysql: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + mysql: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + mysql: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + mysql: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils mysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt + mysqlclient: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + mysqlclient: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + mysqlclient: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + mysqlclient: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils mysqlclient: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt + pymemcache: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymemcache: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymemcache: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymemcache: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pymemcache-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-0.txt pymemcache-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-1.txt pymemcache-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.txt pymemcache-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.txt pymemcache-4: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt + pymongo: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymongo: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymongo: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymongo: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pymongo: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt + psycopg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + psycopg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + psycopg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + psycopg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils py3{8,9}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt py3{10,11}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt pypy3-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + psycopg2: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + psycopg2: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + psycopg2: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + psycopg2: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils psycopg2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt + pymysql: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pymysql: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pymysql: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pymysql: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pymysql: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt + pyramid: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + pyramid: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + pyramid: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + pyramid: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils pyramid: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt + sqlite3: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sqlite3: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sqlite3: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sqlite3: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sqlite3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt + redis: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + redis: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + redis: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + redis: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils redis: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt + remoulade: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + remoulade: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + remoulade: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + remoulade: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils remoulade: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt + requests: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + requests: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + requests: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + requests: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils requests: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt + starlette: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + starlette: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + starlette: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + starlette: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils starlette: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt + system-metrics: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + system-metrics: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + system-metrics: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + system-metrics: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils system-metrics: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt + threading: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + threading: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + threading: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + threading: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils threading: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt + tornado: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + tornado: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + tornado: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + tornado: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils tornado: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt + tortoiseorm: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + tortoiseorm: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + tortoiseorm: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + tortoiseorm: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils tortoiseorm: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt + jinja2: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + jinja2: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + jinja2: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + jinja2: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils jinja2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt + logging: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + logging: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + logging: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + logging: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils logging: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt + aiohttp-client: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiohttp-client: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiohttp-client: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiohttp-client: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiohttp-client: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt + aiohttp-server: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiohttp-server: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiohttp-server: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiohttp-server: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiohttp-server: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt + aiopg: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + aiopg: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + aiopg: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + aiopg: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils aiopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt + richconsole: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + richconsole: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + richconsole: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + richconsole: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils richconsole: pip install -r {toxinidir}/exporter/opentelemetry-exporter-richconsole/test-requirements.txt + prometheus: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + prometheus: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + prometheus: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + prometheus: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils prometheus: pip install -r {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/test-requirements.txt + sklearn: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sklearn: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sklearn: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sklearn: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sklearn: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt + sqlalchemy: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sqlalchemy: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sqlalchemy: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sqlalchemy: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + elasticsearch: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + elasticsearch: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + elasticsearch: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + elasticsearch: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils elasticsearch: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt + asyncio: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + asyncio: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + asyncio: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + asyncio: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils asyncio: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt - ; The numbers at the end of the environment names - ; below mean these dependencies are being used: - ; 0: httpx>=0.18.0,<0.19.0 respx~=0.17.0 - ; 1: httpx>=0.19.0 respx~=0.20.1 + httpx: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + httpx: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + httpx: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + httpx: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils httpx-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-0.txt httpx-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt + sdk-extension-aws: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + sdk-extension-aws: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + sdk-extension-aws: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + sdk-extension-aws: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sdk-extension-aws: pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt + resource-detector-container: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + resource-detector-container: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + resource-detector-container: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + resource-detector-container: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils resource-detector-container: pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/test-requirements.txt - http: pip install {toxinidir}/util/opentelemetry-util-http -; In order to get a health coverage report, + propagator-ot-trace: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + propagator-ot-trace: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + propagator-ot-trace: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + propagator-ot-trace: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils propagator-ot-trace: pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt + propagator-aws-xray: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + propagator-aws-xray: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + propagator-aws-xray: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk + propagator-aws-xray: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils propagator-aws-xray: pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt + processor-baggage: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api + processor-baggage: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions + processor-baggage: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk processor-baggage: pip install -r {toxinidir}/processor/opentelemetry-processor-baggage/test-requirements.txt + http: pip install {toxinidir}/util/opentelemetry-util-http + +; In order to get a health coverage report, ; we have to install packages in editable mode. coverage: python {toxinidir}/scripts/eachdist.py install --editable From 3291f38e8dbde5d73ba2e0ba2a80fd3632faa1d7 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sun, 28 Apr 2024 16:20:17 +0200 Subject: [PATCH 24/28] elasticsearch: test against elasticsearch 7 (#2431) * Update core repo SHA * elasticsearch: test against elasticsearch 7 --------- Co-authored-by: Diego Hurtado --- .github/workflows/test.yml | 2 +- ...quirements.txt => test-requirements-0.txt} | 2 +- .../test-requirements-1.txt | 22 +++ .../tests/helpers_es7.py | 2 +- .../tests/test_elasticsearch.py | 157 ++++++++++++------ tox.ini | 14 +- 6 files changed, 141 insertions(+), 58 deletions(-) rename instrumentation/opentelemetry-instrumentation-elasticsearch/{test-requirements.txt => test-requirements-0.txt} (96%) create mode 100644 instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 529f70e565..5647f34998 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 + CORE_REPO_SHA: 47d5ad7aae5aef31238ca66e55dc550b307c7b35 jobs: misc: diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt similarity index 96% rename from instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt rename to instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt index 4bd1d0d318..054c8a8047 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt @@ -15,7 +15,7 @@ python-dateutil==2.8.2 six==1.16.0 tomli==2.0.1 typing_extensions==4.10.0 -urllib3==2.2.1 +urllib3==1.26.18 wrapt==1.16.0 zipp==3.17.0 -e opentelemetry-instrumentation diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt new file mode 100644 index 0000000000..efa05fd7ff --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt @@ -0,0 +1,22 @@ +asgiref==3.7.2 +attrs==23.2.0 +Deprecated==1.2.14 +elasticsearch==7.17.9 +elasticsearch-dsl==7.4.1 +importlib-metadata==6.11.0 +iniconfig==2.0.0 +packaging==23.2 +pluggy==1.4.0 +py==1.11.0 +py-cpuinfo==9.0.0 +pytest==7.1.3 +pytest-benchmark==4.0.0 +python-dateutil==2.8.2 +six==1.16.0 +tomli==2.0.1 +typing_extensions==4.10.0 +urllib3==1.26.18 +wrapt==1.16.0 +zipp==3.17.0 +-e opentelemetry-instrumentation +-e instrumentation/opentelemetry-instrumentation-elasticsearch diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py index a2d37a54a9..b22df18452 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py @@ -26,6 +26,6 @@ class Index: } } dsl_index_result = (1, {}, '{"result": "created"}') -dsl_index_span_name = "Elasticsearch/test-index/_doc/2" +dsl_index_span_name = "Elasticsearch/test-index/_doc/:id" dsl_index_url = "/test-index/_doc/2" dsl_search_method = "POST" diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py index 5d1c85f77d..690cbe3d4c 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py @@ -50,6 +50,23 @@ # pylint: disable=too-many-public-methods +def normalize_arguments(doc_type, body=None): + if major_version == 7: + return {"document": body} if body else {} + return ( + {"body": body, "doc_type": doc_type} + if body + else {"doc_type": doc_type} + ) + + +def get_elasticsearch_client(*args, **kwargs): + client = Elasticsearch(*args, **kwargs) + if major_version == 7: + client.transport._verified_elasticsearch = True + return client + + @mock.patch( "elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request" ) @@ -79,10 +96,14 @@ def tearDown(self): ElasticsearchInstrumentor().uninstrument() def test_instrumentor(self, request_mock): - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") - es = Elasticsearch() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) @@ -97,20 +118,24 @@ def test_instrumentor(self, request_mock): # check that no spans are generated after uninstrument ElasticsearchInstrumentor().uninstrument() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) def test_span_not_recording(self, request_mock): - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") mock_tracer = mock.Mock() mock_span = mock.Mock() mock_span.is_recording.return_value = False mock_tracer.start_span.return_value = mock_span with mock.patch("opentelemetry.trace.get_tracer") as tracer: tracer.return_value = mock_tracer - Elasticsearch() + get_elasticsearch_client(hosts=["http://localhost:9200"]) self.assertFalse(mock_span.is_recording()) self.assertTrue(mock_span.is_recording.called) self.assertFalse(mock_span.set_attribute.called) @@ -122,7 +147,7 @@ def test_prefix_arg(self, request_mock): prefix = "prefix-from-env" ElasticsearchInstrumentor().uninstrument() ElasticsearchInstrumentor(span_name_prefix=prefix).instrument() - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") self._test_prefix(prefix) def test_prefix_env(self, request_mock): @@ -131,13 +156,17 @@ def test_prefix_env(self, request_mock): os.environ[env_var] = prefix ElasticsearchInstrumentor().uninstrument() ElasticsearchInstrumentor().instrument() - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") del os.environ[env_var] self._test_prefix(prefix) def _test_prefix(self, prefix): - es = Elasticsearch() - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.index( + index="sw", + id=1, + **normalize_arguments(body={"name": "adam"}, doc_type="_doc"), + ) spans_list = self.get_finished_spans() self.assertEqual(len(spans_list), 1) @@ -150,8 +179,10 @@ def test_result_values(self, request_mock): {}, '{"found": false, "timed_out": true, "took": 7}', ) - es = Elasticsearch() - es.get(index="test-index", doc_type="_doc", id=1) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 + ) spans = self.get_finished_spans() @@ -171,14 +202,18 @@ def test_trace_error_unknown(self, request_mock): def test_trace_error_not_found(self, request_mock): msg = "record not found" exc = elasticsearch.exceptions.NotFoundError(404, msg) - request_mock.return_value = (1, {}, {}) + request_mock.return_value = (1, {}, "{}") request_mock.side_effect = exc self._test_trace_error(StatusCode.ERROR, exc) def _test_trace_error(self, code, exc): - es = Elasticsearch() + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) try: - es.get(index="test-index", doc_type="_doc", id=1) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=1, + ) except Exception: # pylint: disable=broad-except pass @@ -192,10 +227,14 @@ def _test_trace_error(self, code, exc): ) def test_parent(self, request_mock): - request_mock.return_value = (1, {}, {}) - es = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) with self.tracer.start_as_current_span("parent"): - es.index(index="sw", doc_type="_doc", id=1, body={"name": "adam"}) + es.index( + index="sw", + **normalize_arguments(doc_type="_doc", body={"name": "adam"}), + id=1, + ) spans = self.get_finished_spans() self.assertEqual(len(spans), 2) @@ -206,8 +245,8 @@ def test_parent(self, request_mock): self.assertEqual(child.parent.span_id, parent.context.span_id) def test_multithread(self, request_mock): - request_mock.return_value = (1, {}, {}) - es = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) ev = threading.Event() # 1. Start tracing from thread-1; make thread-2 wait @@ -215,13 +254,21 @@ def test_multithread(self, request_mock): # 3. Check the spans got different parents, and are in the expected order. def target1(parent_span): with trace.use_span(parent_span): - es.get(index="test-index", doc_type="_doc", id=1) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=1, + ) ev.set() ev.wait() def target2(): ev.wait() - es.get(index="test-index", doc_type="_doc", id=2) + es.get( + index="test-index", + **normalize_arguments(doc_type="_doc"), + id=2, + ) ev.set() with self.tracer.start_as_current_span("parent") as span: @@ -247,7 +294,7 @@ def target2(): def test_dsl_search(self, request_mock): request_mock.return_value = (1, {}, '{"hits": {"hits": []}}') - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) search = Search(using=client, index="test-index").filter( "term", author="testing" ) @@ -264,7 +311,7 @@ def test_dsl_search(self, request_mock): def test_dsl_search_sanitized(self, request_mock): request_mock.return_value = (1, {}, '{"hits": {"hits": []}}') - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) search = Search(using=client, index="test-index").filter( "term", author="testing" ) @@ -280,8 +327,8 @@ def test_dsl_search_sanitized(self, request_mock): ) def test_dsl_create(self, request_mock): - request_mock.return_value = (1, {}, {}) - client = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) Article.init(using=client) spans = self.get_finished_spans() @@ -307,8 +354,8 @@ def test_dsl_create(self, request_mock): ) def test_dsl_create_sanitized(self, request_mock): - request_mock.return_value = (1, {}, {}) - client = Elasticsearch() + request_mock.return_value = (1, {}, "{}") + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) Article.init(using=client) spans = self.get_finished_spans() @@ -323,9 +370,9 @@ def test_dsl_create_sanitized(self, request_mock): ) def test_dsl_index(self, request_mock): - request_mock.return_value = helpers.dsl_index_result + request_mock.return_value = (1, {}, helpers.dsl_index_result[2]) - client = Elasticsearch() + client = get_elasticsearch_client(hosts=["http://localhost:9200"]) article = Article( meta={"id": 2}, title="About searching", @@ -374,11 +421,16 @@ def request_hook(span, method, url, kwargs): {}, '{"found": false, "timed_out": true, "took": 7}', ) - es = Elasticsearch() + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) index = "test-index" doc_id = 1 - kwargs = {"params": {"test": True}} - es.get(index=index, doc_type="_doc", id=doc_id, **kwargs) + kwargs = {"params": {"refresh": True, "realtime": True}} + es.get( + index=index, + id=doc_id, + **normalize_arguments(doc_type="_doc"), + **kwargs, + ) spans = self.get_finished_spans() @@ -386,12 +438,21 @@ def request_hook(span, method, url, kwargs): self.assertEqual( "GET", spans[0].attributes[request_hook_method_attribute] ) + expected_url = f"/{index}/_doc/{doc_id}" self.assertEqual( - f"/{index}/_doc/{doc_id}", + expected_url, spans[0].attributes[request_hook_url_attribute], ) + + if major_version == 7: + expected_kwargs = { + **kwargs, + "headers": {"accept": "application/json"}, + } + else: + expected_kwargs = {**kwargs} self.assertEqual( - json.dumps(kwargs), + json.dumps(expected_kwargs), spans[0].attributes[request_hook_kwargs_attribute], ) @@ -431,13 +492,11 @@ def response_hook(span, response): }, } - request_mock.return_value = ( - 1, - {}, - json.dumps(response_payload), + request_mock.return_value = (1, {}, json.dumps(response_payload)) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 ) - es = Elasticsearch() - es.get(index="test-index", doc_type="_doc", id=1) spans = self.get_finished_spans() @@ -453,13 +512,11 @@ def test_no_op_tracer_provider(self, request_mock): tracer_provider=trace.NoOpTracerProvider() ) response_payload = '{"found": false, "timed_out": true, "took": 7}' - request_mock.return_value = ( - 1, - {}, - response_payload, + request_mock.return_value = (1, {}, response_payload) + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) + res = es.get( + index="test-index", **normalize_arguments(doc_type="_doc"), id=1 ) - es = Elasticsearch() - res = es.get(index="test-index", doc_type="_doc", id=1) self.assertEqual( res.get("found"), json.loads(response_payload).get("found") ) @@ -486,11 +543,11 @@ def test_body_sanitization(self, _): ) def test_bulk(self, request_mock): - request_mock.return_value = (1, {}, "") + request_mock.return_value = (1, {}, "{}") - es = Elasticsearch() + es = get_elasticsearch_client(hosts=["http://localhost:9200"]) es.bulk( - [ + body=[ { "_op_type": "index", "_index": "sw", diff --git a/tox.ini b/tox.ini index 783f66e064..cbe9c7d981 100644 --- a/tox.ini +++ b/tox.ini @@ -75,9 +75,12 @@ envlist = ; pypy3-test-instrumentation-boto ; opentelemetry-instrumentation-elasticsearch - ; FIXME: Elasticsearch >=7 causes CI workflow tests to hang, see open-telemetry/opentelemetry-python-contrib#620 - py3{8,9,10,11}-test-instrumentation-elasticsearch - pypy3-test-instrumentation-elasticsearch + ; The numbers at the end of the environment names + ; below mean these dependencies are being used: + ; 0: elasticsearch-dsl==6.4.0 elasticsearch==6.8.2 + ; 1: elasticsearch-dsl==7.4.1 elasticsearch==7.17.9 + py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,1} + pypy3-test-instrumentation-elasticsearch-{0,1} ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 @@ -640,7 +643,8 @@ commands_pre = elasticsearch: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions elasticsearch: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk elasticsearch: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils - elasticsearch: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt + elasticsearch-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt + elasticsearch-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt asyncio: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api asyncio: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -830,7 +834,7 @@ commands_pre = # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install # for your OS to install the required dependencies pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements.txt + pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt From 58f3d87b78cbd773c9aba34e4386510505de4375 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 29 Apr 2024 19:35:04 +0200 Subject: [PATCH 25/28] gen-requirements: Bump jinja to latest one (#2463) --- gen-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen-requirements.txt b/gen-requirements.txt index 0f96f12a56..de84b72c1e 100644 --- a/gen-requirements.txt +++ b/gen-requirements.txt @@ -1,6 +1,6 @@ -c dev-requirements.txt astor==0.8.1 -jinja2~=2.7 +jinja2==3.1.3 markupsafe==2.0.1 isort black From 2493258af11df7f211567103635588f2813de7a3 Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Mon, 29 Apr 2024 10:53:01 -0700 Subject: [PATCH 26/28] Ignore vm detector if already in other rps for azure resource detector (#2456) --- .../CHANGELOG.md | 12 +++- .../resource/detector/azure/__init__.py | 25 +++++++ .../resource/detector/azure/_constants.py | 68 +++++++++++++++++++ .../resource/detector/azure/_utils.py | 37 ++++++++++ .../resource/detector/azure/app_service.py | 24 ++----- .../resource/detector/azure/vm.py | 43 +++++------- .../tests/test_vm.py | 10 +++ 7 files changed, 174 insertions(+), 45 deletions(-) create mode 100644 resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py create mode 100644 resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py create mode 100644 resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py diff --git a/resource/opentelemetry-resource-detector-azure/CHANGELOG.md b/resource/opentelemetry-resource-detector-azure/CHANGELOG.md index f92a5db8b1..8954fc5359 100644 --- a/resource/opentelemetry-resource-detector-azure/CHANGELOG.md +++ b/resource/opentelemetry-resource-detector-azure/CHANGELOG.md @@ -7,9 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Ignore vm detector if already in other rps + ([#2456](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2456)) + +## Version 0.1.4 (2024-04-05) + +- Fix windows tests/suppress instrumentation for urllib call + ([#2178](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2178)) + +## Version 0.1.3 (2024-01-25) + - Change meta data service timeout to 200ms ([#2387](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2387)) -## Version 0.1.2 (2024-01-25) +## Version 0.1.1 (2024-01-10) - Initial CHANGELOG.md entry diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py new file mode 100644 index 0000000000..913b677c3e --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/__init__.py @@ -0,0 +1,25 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pylint: disable=import-error + +from .app_service import AzureAppServiceResourceDetector +from .version import __version__ +from .vm import AzureVMResourceDetector + +__all__ = [ + "AzureAppServiceResourceDetector", + "AzureVMResourceDetector", + "__version__", +] diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py new file mode 100644 index 0000000000..dddc6632ac --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_constants.py @@ -0,0 +1,68 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from opentelemetry.semconv.resource import ResourceAttributes + +# cSpell:disable + +# Azure Kubernetes + +_AKS_ARM_NAMESPACE_ID = "AKS_ARM_NAMESPACE_ID" + +# AppService + +_AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE = "azure.app.service.stamp" +_REGION_NAME = "REGION_NAME" +_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME" +_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME" +_WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID" +_WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME" +_WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP" +_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME" +_WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME" + +_APP_SERVICE_ATTRIBUTE_ENV_VARS = { + ResourceAttributes.CLOUD_REGION: _REGION_NAME, + ResourceAttributes.DEPLOYMENT_ENVIRONMENT: _WEBSITE_SLOT_NAME, + ResourceAttributes.HOST_ID: _WEBSITE_HOSTNAME, + ResourceAttributes.SERVICE_INSTANCE_ID: _WEBSITE_INSTANCE_ID, + _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE: _WEBSITE_HOME_STAMPNAME, +} + +# Functions + +_FUNCTIONS_WORKER_RUNTIME = "FUNCTIONS_WORKER_RUNTIME" + +# Vm + +_AZURE_VM_METADATA_ENDPOINT = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json" +_AZURE_VM_SCALE_SET_NAME_ATTRIBUTE = "azure.vm.scaleset.name" +_AZURE_VM_SKU_ATTRIBUTE = "azure.vm.sku" + +_EXPECTED_AZURE_AMS_ATTRIBUTES = [ + _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE, + _AZURE_VM_SKU_ATTRIBUTE, + ResourceAttributes.CLOUD_PLATFORM, + ResourceAttributes.CLOUD_PROVIDER, + ResourceAttributes.CLOUD_REGION, + ResourceAttributes.CLOUD_RESOURCE_ID, + ResourceAttributes.HOST_ID, + ResourceAttributes.HOST_NAME, + ResourceAttributes.HOST_TYPE, + ResourceAttributes.OS_TYPE, + ResourceAttributes.OS_VERSION, + ResourceAttributes.SERVICE_INSTANCE_ID, +] + +# cSpell:enable diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py new file mode 100644 index 0000000000..3f73613945 --- /dev/null +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/_utils.py @@ -0,0 +1,37 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from ._constants import ( + _AKS_ARM_NAMESPACE_ID, + _FUNCTIONS_WORKER_RUNTIME, + _WEBSITE_SITE_NAME, +) + + +def _is_on_aks() -> bool: + return os.environ.get(_AKS_ARM_NAMESPACE_ID) is not None + + +def _is_on_app_service() -> bool: + return os.environ.get(_WEBSITE_SITE_NAME) is not None + + +def _is_on_functions() -> bool: + return os.environ.get(_FUNCTIONS_WORKER_RUNTIME) is not None + + +def _can_ignore_vm_detect() -> bool: + return _is_on_aks() or _is_on_app_service() or _is_on_functions() diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py index b4daa4cc84..613d8f9410 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/app_service.py @@ -21,24 +21,12 @@ ResourceAttributes, ) -_AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE = "azure.app.service.stamp" -_REGION_NAME = "REGION_NAME" -_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME" -_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME" -_WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID" -_WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME" -_WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP" -_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME" -_WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME" - - -_APP_SERVICE_ATTRIBUTE_ENV_VARS = { - ResourceAttributes.CLOUD_REGION: _REGION_NAME, - ResourceAttributes.DEPLOYMENT_ENVIRONMENT: _WEBSITE_SLOT_NAME, - ResourceAttributes.HOST_ID: _WEBSITE_HOSTNAME, - ResourceAttributes.SERVICE_INSTANCE_ID: _WEBSITE_INSTANCE_ID, - _AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE: _WEBSITE_HOME_STAMPNAME, -} +from ._constants import ( + _APP_SERVICE_ATTRIBUTE_ENV_VARS, + _WEBSITE_OWNER_NAME, + _WEBSITE_RESOURCE_GROUP, + _WEBSITE_SITE_NAME, +) class AzureAppServiceResourceDetector(ResourceDetector): diff --git a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py index da4c6563a5..2112282949 100644 --- a/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py +++ b/resource/opentelemetry-resource-detector-azure/src/opentelemetry/resource/detector/azure/vm.py @@ -30,40 +30,31 @@ ResourceAttributes, ) -_AZURE_VM_METADATA_ENDPOINT = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json" -_AZURE_VM_SCALE_SET_NAME_ATTRIBUTE = "azure.vm.scaleset.name" -_AZURE_VM_SKU_ATTRIBUTE = "azure.vm.sku" -_logger = getLogger(__name__) - -EXPECTED_AZURE_AMS_ATTRIBUTES = [ +from ._constants import ( + _AZURE_VM_METADATA_ENDPOINT, _AZURE_VM_SCALE_SET_NAME_ATTRIBUTE, _AZURE_VM_SKU_ATTRIBUTE, - ResourceAttributes.CLOUD_PLATFORM, - ResourceAttributes.CLOUD_PROVIDER, - ResourceAttributes.CLOUD_REGION, - ResourceAttributes.CLOUD_RESOURCE_ID, - ResourceAttributes.HOST_ID, - ResourceAttributes.HOST_NAME, - ResourceAttributes.HOST_TYPE, - ResourceAttributes.OS_TYPE, - ResourceAttributes.OS_VERSION, - ResourceAttributes.SERVICE_INSTANCE_ID, -] + _EXPECTED_AZURE_AMS_ATTRIBUTES, +) +from ._utils import _can_ignore_vm_detect + +_logger = getLogger(__name__) class AzureVMResourceDetector(ResourceDetector): # pylint: disable=no-self-use def detect(self) -> "Resource": attributes = {} - token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) - metadata_json = _get_azure_vm_metadata() - if not metadata_json: - return Resource(attributes) - for attribute_key in EXPECTED_AZURE_AMS_ATTRIBUTES: - attributes[attribute_key] = _get_attribute_from_metadata( - metadata_json, attribute_key - ) - detach(token) + if not _can_ignore_vm_detect(): + token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) + metadata_json = _get_azure_vm_metadata() + if not metadata_json: + return Resource(attributes) + for attribute_key in _EXPECTED_AZURE_AMS_ATTRIBUTES: + attributes[attribute_key] = _get_attribute_from_metadata( + metadata_json, attribute_key + ) + detach(token) return Resource(attributes) diff --git a/resource/opentelemetry-resource-detector-azure/tests/test_vm.py b/resource/opentelemetry-resource-detector-azure/tests/test_vm.py index 86aa373d3c..56d7d39104 100644 --- a/resource/opentelemetry-resource-detector-azure/tests/test_vm.py +++ b/resource/opentelemetry-resource-detector-azure/tests/test_vm.py @@ -378,3 +378,13 @@ def test_windows(self, mock_urlopen): attributes = AzureVMResourceDetector().detect().attributes for attribute_key, attribute_value in WINDOWS_ATTRIBUTES.items(): self.assertEqual(attributes[attribute_key], attribute_value) + + @patch("opentelemetry.resource.detector.azure.vm._can_ignore_vm_detect") + @patch("opentelemetry.resource.detector.azure.vm.urlopen") + def test_in_another_rp(self, mock_urlopen, detect_mock): + mock_urlopen.return_value.__enter__.return_value.read.return_value = ( + LINUX_JSON + ) + detect_mock.return_value = True + attributes = AzureVMResourceDetector().detect().attributes + self.assertEqual(attributes, {}) From de7ce0fb2274aafdcf86d5a95825e8f34a4dd6ec Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 29 Apr 2024 20:49:08 +0200 Subject: [PATCH 27/28] Use local imports when importing from tests (#2464) --- .../tests/test_aws_lambda_instrumentation_manual.py | 12 +++++------- .../tests/test_client_interceptor.py | 4 +--- .../tests/test_client_interceptor_filter.py | 4 +--- .../tests/test_client_interceptor_hooks.py | 4 +--- .../tests/test_pymemcache.py | 5 ++--- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py index a2730028e8..f10953c754 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py @@ -17,13 +17,6 @@ from typing import Any, Callable, Dict from unittest import mock -from tests.mocks.api_gateway_http_api_event import ( - MOCK_LAMBDA_API_GATEWAY_HTTP_API_EVENT, -) -from tests.mocks.api_gateway_proxy_event import ( - MOCK_LAMBDA_API_GATEWAY_PROXY_EVENT, -) - from opentelemetry.environment_variables import OTEL_PROPAGATORS from opentelemetry.instrumentation.aws_lambda import ( _HANDLER, @@ -45,6 +38,11 @@ TraceContextTextMapPropagator, ) +from .mocks.api_gateway_http_api_event import ( + MOCK_LAMBDA_API_GATEWAY_HTTP_API_EVENT, +) +from .mocks.api_gateway_proxy_event import MOCK_LAMBDA_API_GATEWAY_PROXY_EVENT + class MockLambdaContext: def __init__(self, aws_request_id, invoked_function_arn): diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py index 2436aca40c..38759352b3 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor.py @@ -14,9 +14,6 @@ # pylint:disable=cyclic-import import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) import opentelemetry.instrumentation.grpc from opentelemetry import trace @@ -41,6 +38,7 @@ simple_method_future, ) from ._server import create_test_server +from .protobuf import test_server_pb2_grpc from .protobuf.test_server_pb2 import Request diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py index 9a9aefad59..b6ae975dff 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_filter.py @@ -17,9 +17,6 @@ from unittest import mock import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) import opentelemetry.instrumentation.grpc from opentelemetry import trace @@ -44,6 +41,7 @@ simple_method_future, ) from ._server import create_test_server +from .protobuf import test_server_pb2_grpc from .protobuf.test_server_pb2 import Request diff --git a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py index ca649f7bb1..aeecffc71c 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/tests/test_client_interceptor_hooks.py @@ -13,9 +13,6 @@ # limitations under the License. import grpc -from tests.protobuf import ( # pylint: disable=no-name-in-module - test_server_pb2_grpc, -) from opentelemetry import trace from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient @@ -23,6 +20,7 @@ from ._client import simple_method from ._server import create_test_server +from .protobuf import test_server_pb2_grpc # User defined interceptor. Is used in the tests along with the opentelemetry client interceptor. diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py index 35b672bac0..4e29091217 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/tests/test_pymemcache.py @@ -24,15 +24,14 @@ MemcacheUnknownError, ) -# pylint: disable=import-error,no-name-in-module -from tests.utils import MockSocket, _str - from opentelemetry import trace as trace_api from opentelemetry.instrumentation.pymemcache import PymemcacheInstrumentor from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer +from .utils import MockSocket, _str + TEST_HOST = "localhost" TEST_PORT = 117711 From 5116305f77bcd4c8ab18ef302a4351bb5b724c1e Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 30 Apr 2024 09:05:49 -0500 Subject: [PATCH 28/28] Separate lint into several jobs (#2467) * Separate lint for flask * Seaparate lint for resource-detector-container * Add linting workflow * Update contributing documentation * Fix lint workflow * Add fix for resource-detector-container * Separate lint for sdk-extension-aws * Separate lint for distro * Separate lint for opentelemetry-instrumentation * Separate lint for aiohttp-client * Separate lint for aiohttp-server * Separate lint for aiopg * Separate lint for aws-lambda * Separate lint for botocore * Separate lint for boto3sqs * Separate lint for django * Separate lint for dbapi * Separate lint for boto * Separate lint for elasticsearch * Separate lint for falcon * Separate lint for fastapi * Separate lint for urllib * Separate lint for urllib3 * Separate lint for requests * Separate lint for starlette * Separate lint for jinja2 * Seaparate lint for logging and richconsole * Separate lint for prometheus-remote-write * Separate lint for mysql * Separate lint for mysqlclient * Separate lint for psycopg2 * Separate lint for psycopg * Separate lint for pymemcache * Separate lint for pymongo * Separate lint for pymysql * Separate lint for pyramid * Separate lint for asgi * Separate lint for asyncpg * Separate lint for sqlite3 * Separate lint for wsgi * Separate lint for grpc * Separate lint for sqlalchemy * Separate lint for redis * Separate lint for remoulade * Separate lint for celery and sklearn * Separate lint for system-metrics * Separate lint for threading * Separate lint for tornado * Separate lint for tortoiseorm * Separate lint for httpx * Separate lint for propagator-aws-xray * Remove lint * Separate lint for propagator-ot-trace * Separate lint for sio-pika * Separate lint for aio-pika * Fix aio and sio pika * Separate lint for kafka-python * Separate lint for confluent-kafka * Separate lint for asyncio * Separate lint for cassandra * Separate lint for processor-baggage * Remove lint test environment * Rename lint workflow file * Fix sio-pika lint testing package path * More fixes * Fix linting for opentelemetry-instrumentation * Add section for linting with 3.8 * Add missing lint install command for elasticsearch * Sorted packages --- .github/workflows/lint.yml | 121 +++++++++ .github/workflows/test.yml | 5 +- CONTRIBUTING.md | 6 +- tox.ini | 495 +++++++++++++++++++++++++++++++------ 4 files changed, 543 insertions(+), 84 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..39afb3ee96 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,121 @@ +name: Lint tests + +on: + push: + branches-ignore: + - 'release/*' + pull_request: +env: + CORE_REPO_SHA: 955c92e91b5cd4bcfb43c39efcef086b040471d2 + +jobs: + lint-3_11: + strategy: + fail-fast: false # ensures the entire test matrix is run, even if one permutation fails + matrix: + package: + - "distro" + - "exporter-prometheus-remote-write" + - "exporter-richconsole" + - "instrumentation-aio-pika" + - "instrumentation-aiohttp-client" + - "instrumentation-aiohttp-server" + - "instrumentation-aiopg" + - "instrumentation-asgi" + - "instrumentation-asyncio" + - "instrumentation-asyncpg" + - "instrumentation-aws-lambda" + - "instrumentation-boto" + - "instrumentation-boto3sqs" + - "instrumentation-botocore" + - "instrumentation-cassandra" + - "instrumentation-celery" + - "instrumentation-confluent-kafka" + - "instrumentation-dbapi" + - "instrumentation-django" + - "instrumentation-elasticsearch" + - "instrumentation-falcon" + - "instrumentation-fastapi" + - "instrumentation-flask" + - "instrumentation-grpc" + - "instrumentation-httpx" + - "instrumentation-jinja2" + - "instrumentation-kafka-python" + - "instrumentation-logging" + - "instrumentation-mysql" + - "instrumentation-mysqlclient" + - "instrumentation-psycopg" + - "instrumentation-psycopg2" + - "instrumentation-pymemcache" + - "instrumentation-pymongo" + - "instrumentation-pymysql" + - "instrumentation-pyramid" + - "instrumentation-redis" + - "instrumentation-remoulade" + - "instrumentation-requests" + - "instrumentation-sio-pika" + - "instrumentation-sqlalchemy" + - "instrumentation-sqlite3" + - "instrumentation-starlette" + - "instrumentation-system-metrics" + - "instrumentation-threading" + - "instrumentation-tornado" + - "instrumentation-tortoiseorm" + - "instrumentation-urllib" + - "instrumentation-urllib3" + - "instrumentation-wsgi" + - "opentelemetry-instrumentation" + - "processor-baggage" + - "propagator-aws-xray" + - "propagator-ot-trace" + - "resource-detector-container" + - "sdk-extension-aws" + os: [ubuntu-20.04] + runs-on: ubuntu-20.04 + steps: + - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install tox + run: pip install tox + - name: Cache tox environment + # Preserves .tox directory between runs for faster installs + uses: actions/cache@v4 + with: + path: | + .tox + ~/.cache/pip + key: v7-build-tox-cache-${{ matrix.package }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} + - name: run tox + run: tox -e lint-${{ matrix.package }} + + lint-3_8: + strategy: + fail-fast: false # ensures the entire test matrix is run, even if one permutation fails + matrix: + package: + - "instrumentation-sklearn" + os: [ubuntu-20.04] + runs-on: ubuntu-20.04 + steps: + - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + - name: Set up Python 3.8 + uses: actions/setup-python@v5 + with: + python-version: 3.8 + - name: Install tox + run: pip install tox + - name: Cache tox environment + # Preserves .tox directory between runs for faster installs + uses: actions/cache@v4 + with: + path: | + .tox + ~/.cache/pip + key: v7-build-tox-cache-${{ matrix.package }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} + - name: run tox + run: tox -e lint-${{ matrix.package }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5647f34998..a129c6e7ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - tox-environment: [ "docker-tests", "spellcheck", "lint", "docs", "generate" ] + tox-environment: [ "docker-tests", "spellcheck", "docs", "generate" ] name: ${{ matrix.tox-environment }} runs-on: ubuntu-20.04 steps: @@ -25,9 +25,6 @@ jobs: python-version: "3.10" - name: Install tox run: pip install tox - - name: Install libsnappy-dev - if: ${{ matrix.tox-environment == 'lint' }} - run: sudo apt-get install -y libsnappy-dev - name: Cache tox environment # Preserves .tox directory between runs for faster installs uses: actions/cache@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c18392bc7..3c4bae0f47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,13 +62,13 @@ You can run `tox` with the following arguments: - `tox -e py311-test-instrumentation-aiopg` to e.g. run the aiopg instrumentation unit tests under a specific Python version - `tox -e spellcheck` to run a spellcheck on all the code -- `tox -e lint` to run lint checks on all code +- `tox -e lint-some-package` to run lint checks on `some-package` `black` and `isort` are executed when `tox -e lint` is run. The reported errors can be tedious to fix manually. An easier way to do so is: -1. Run `.tox/lint/bin/black .` -2. Run `.tox/lint/bin/isort .` +1. Run `.tox/lint-some-package/bin/black .` +2. Run `.tox/lint-some-package/bin/isort .` See [`tox.ini`](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/tox.ini) diff --git a/tox.ini b/tox.ini index cbe9c7d981..ed74e485cd 100644 --- a/tox.ini +++ b/tox.ini @@ -9,44 +9,54 @@ envlist = ; opentelemetry-resource-detector-container py3{8,9,10,11}-test-resource-detector-container pypy3-test-resource-detector-container + lint-resource-detector-container ; opentelemetry-sdk-extension-aws py3{8,9,10,11}-test-sdk-extension-aws pypy3-test-sdk-extension-aws + lint-sdk-extension-aws ; opentelemetry-distro py3{8,9,10,11}-test-distro pypy3-test-distro + lint-distro ; opentelemetry-instrumentation py3{8,9,10,11}-test-opentelemetry-instrumentation pypy3-test-opentelemetry-instrumentation + lint-opentelemetry-instrumentation ; opentelemetry-instrumentation-aiohttp-client py3{8,9,10,11}-test-instrumentation-aiohttp-client pypy3-test-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client ; opentelemetry-instrumentation-aiohttp-server py3{8,9,10,11}-test-instrumentation-aiohttp-server pypy3-test-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server ; opentelemetry-instrumentation-aiopg py3{8,9,10,11}-test-instrumentation-aiopg ; instrumentation-aiopg intentionally excluded from pypy3 + lint-instrumentation-aiopg ; opentelemetry-instrumentation-aws-lambda py3{8,9,10,11}-test-instrumentation-aws-lambda pypy3-test-instrumentation-aws-lambda + lint-instrumentation-aws-lambda ; opentelemetry-instrumentation-botocore py3{8,9,10,11}-test-instrumentation-botocore ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-botocore + lint-instrumentation-botocore ; opentelemetry-instrumentation-boto3sqs py3{8,9,10,11}-test-instrumentation-boto3sqs ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-boto3sqs + lint-instrumentation-boto3sqs ; opentelemetry-instrumentation-django ; Only officially supported Python versions are tested for each Django @@ -64,15 +74,18 @@ envlist = py3{10,11}-test-instrumentation-django-1 py3{10,11}-test-instrumentation-django-3 pypy3-test-instrumentation-django-{0,1} + lint-instrumentation-django ; opentelemetry-instrumentation-dbapi py3{8,9,10,11}-test-instrumentation-dbapi pypy3-test-instrumentation-dbapi + lint-instrumentation-dbapi ; opentelemetry-instrumentation-boto py3{8,9,10,11}-test-instrumentation-boto ; FIXME: see https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1736 ; pypy3-test-instrumentation-boto + lint-instrumentation-boto ; opentelemetry-instrumentation-elasticsearch ; The numbers at the end of the environment names @@ -81,6 +94,7 @@ envlist = ; 1: elasticsearch-dsl==7.4.1 elasticsearch==7.17.9 py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,1} pypy3-test-instrumentation-elasticsearch-{0,1} + lint-instrumentation-elasticsearch ; opentelemetry-instrumentation-falcon ; py310 does not work with falcon 1 @@ -92,10 +106,12 @@ envlist = py3{8,9}-test-instrumentation-falcon-0 py3{8,9,10,11}-test-instrumentation-falcon-{1,2} pypy3-test-instrumentation-falcon-{0,1,2} + lint-instrumentation-falcon ; opentelemetry-instrumentation-fastapi py3{8,9,10,11}-test-instrumentation-fastapi pypy3-test-instrumentation-fastapi + lint-instrumentation-fastapi ; opentelemetry-instrumentation-flask ; The numbers at the end of the environment names @@ -106,10 +122,12 @@ envlist = py3{8,9,10,11}-test-instrumentation-flask-{0,1} py3{8,9,10,11}-test-instrumentation-flask-{2} pypy3-test-instrumentation-flask-{0,1} + lint-instrumentation-flask ; opentelemetry-instrumentation-urllib py3{8,9,10,11}-test-instrumentation-urllib pypy3-test-instrumentation-urllib + lint-instrumentation-urllib ; opentelemetry-instrumentation-urllib3 ; The numbers at the end of the environment names @@ -118,46 +136,60 @@ envlist = ; 1: urllib3 >=2.0.0,<3.0.0 py3{8,9,10,11}-test-instrumentation-urllib3-{0,1} pypy3-test-instrumentation-urllib3-{0,1} + lint-instrumentation-urllib3 ; opentelemetry-instrumentation-requests py3{8,9,10,11}-test-instrumentation-requests ;pypy3-test-instrumentation-requests + lint-instrumentation-requests ; opentelemetry-instrumentation-starlette py3{8,9,10,11}-test-instrumentation-starlette pypy3-test-instrumentation-starlette + lint-instrumentation-starlette ; opentelemetry-instrumentation-jinja2 py3{8,9,10,11}-test-instrumentation-jinja2 pypy3-test-instrumentation-jinja2 + lint-instrumentation-jinja2 ; opentelemetry-instrumentation-logging py3{8,9,10,11}-test-instrumentation-logging pypy3-test-instrumentation-logging + lint-instrumentation-logging ; opentelemetry-exporter-richconsole py3{8,9,10,11}-test-exporter-richconsole pypy3-test-exporter-richconsole + lint-exporter-richconsole ; opentelemetry-exporter-prometheus-remote-write py3{8,9,10,11}-test-exporter-prometheus-remote-write pypy3-test-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write ; opentelemetry-instrumentation-mysql py3{8,9,10,11}-test-instrumentation-mysql pypy3-test-instrumentation-mysql + lint-instrumentation-mysql ; opentelemetry-instrumentation-mysqlclient py3{8,9,10,11}-test-instrumentation-mysqlclient pypy3-test-instrumentation-mysqlclient + ; prerequisite: follow the instructions here + ; https://github.com/PyMySQL/mysqlclient#install + ; for your OS to install the required dependencies + lint-instrumentation-mysqlclient ; opentelemetry-instrumentation-psycopg2 py3{8,9,10,11}-test-instrumentation-psycopg2 ; ext-psycopg2 intentionally excluded from pypy3 + lint-instrumentation-psycopg2 ; opentelemetry-instrumentation-psycopg py3{8,9,10,11}-test-instrumentation-psycopg pypy3-test-instrumentation-psycopg + lint-instrumentation-psycopg ; opentelemetry-instrumentation-pymemcache ; The numbers at the end of the environment names @@ -169,38 +201,47 @@ envlist = ; 4: pymemcache ==4.0.0 py3{8,9,10,11}-test-instrumentation-pymemcache-{0,1,2,3,4} pypy3-test-instrumentation-pymemcache-{0,1,2,3,4} + lint-instrumentation-pymemcache ; opentelemetry-instrumentation-pymongo py3{8,9,10,11}-test-instrumentation-pymongo pypy3-test-instrumentation-pymongo + lint-instrumentation-pymongo ; opentelemetry-instrumentation-pymysql py3{8,9,10,11}-test-instrumentation-pymysql pypy3-test-instrumentation-pymysql + lint-instrumentation-pymysql ; opentelemetry-instrumentation-pyramid py3{8,9,10,11}-test-instrumentation-pyramid pypy3-test-instrumentation-pyramid + lint-instrumentation-pyramid ; opentelemetry-instrumentation-asgi py3{8,9,10,11}-test-instrumentation-asgi pypy3-test-instrumentation-asgi + lint-instrumentation-asgi ; opentelemetry-instrumentation-asyncpg py3{8,9,10,11}-test-instrumentation-asyncpg ; ext-asyncpg intentionally excluded from pypy3 + lint-instrumentation-asyncpg ; opentelemetry-instrumentation-sqlite3 py3{8,9,10,11}-test-instrumentation-sqlite3 pypy3-test-instrumentation-sqlite3 + lint-instrumentation-sqlite3 ; opentelemetry-instrumentation-wsgi py3{8,9,10,11}-test-instrumentation-wsgi pypy3-test-instrumentation-wsgi + lint-instrumentation-wsgi ; opentelemetry-instrumentation-grpc py3{8,9,10,11}-test-instrumentation-grpc pypy3-test-instrumentation-grpc + lint-instrumentation-grpc ; opentelemetry-instrumentation-sqlalchemy ; The numbers at the end of the environment names @@ -209,37 +250,46 @@ envlist = ; 1: sqlalchemy~=1.4 aiosqlite py3{8,9,10,11}-test-instrumentation-sqlalchemy-{1} pypy3-test-instrumentation-sqlalchemy-{0,1} + lint-instrumentation-sqlalchemy ; opentelemetry-instrumentation-redis py3{8,9,10,11}-test-instrumentation-redis pypy3-test-instrumentation-redis + lint-instrumentation-redis ; opentelemetry-instrumentation-remoulade py3{8,9,10,11}-test-instrumentation-remoulade ; instrumentation-remoulade intentionally excluded from pypy3 + lint-instrumentation-remoulade ; opentelemetry-instrumentation-celery py3{8,9,10,11}-test-instrumentation-celery pypy3-test-instrumentation-celery + lint-instrumentation-celery ; opentelemetry-instrumentation-sklearn py3{8}-test-instrumentation-sklearn + lint-instrumentation-sklearn ; opentelemetry-instrumentation-system-metrics py3{8,9,10,11}-test-instrumentation-system-metrics pypy3-test-instrumentation-system-metrics + lint-instrumentation-system-metrics ; opentelemetry-instrumentation-threading py3{8,9,10,11}-test-instrumentation-threading pypy3-test-instrumentation-threading + lint-instrumentation-threading ; opentelemetry-instrumentation-tornado py3{8,9,10,11}-test-instrumentation-tornado pypy3-test-instrumentation-tornado + lint-instrumentation-tornado ; opentelemetry-instrumentation-tortoiseorm py3{8,9,10,11}-test-instrumentation-tortoiseorm pypy3-test-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm ; opentelemetry-instrumentation-httpx ; The numbers at the end of the environment names @@ -248,6 +298,7 @@ envlist = ; 1: httpx>=0.19.0 respx~=0.20.1 py3{8,9,10,11}-test-instrumentation-httpx-{0,1} pypy3-test-instrumentation-httpx-{0,1} + lint-instrumentation-httpx ; opentelemetry-util-http py3{8,9,10,11}-test-util-http @@ -256,10 +307,12 @@ envlist = ; opentelemetry-propagator-aws-xray py3{8,9,10,11}-test-propagator-aws-xray pypy3-test-propagator-aws-xray + lint-propagator-aws-xray ; opentelemetry-propagator-ot-trace py3{8,9,10,11}-test-propagator-ot-trace pypy3-test-propagator-ot-trace + lint-propagator-ot-trace ; opentelemetry-instrumentation-sio-pika ; The numbers at the end of the environment names @@ -268,6 +321,7 @@ envlist = ; 1: pika>=1.0.0 py3{8,9,10,11}-test-instrumentation-sio-pika-{0,1} pypy3-test-instrumentation-sio-pika-{0,1} + lint-instrumentation-sio-pika ; opentelemetry-instrumentation-aio-pika ; The numbers at the end of the environment names @@ -278,27 +332,33 @@ envlist = ; 3: aio_pika==9.4.1 py3{8,9,10,11}-test-instrumentation-aio-pika-{0,1,2,3} pypy3-test-instrumentation-aio-pika-{0,1,2,3} + lint-instrumentation-aio-pika ; opentelemetry-instrumentation-kafka-python py3{8,9,10,11}-test-instrumentation-kafka-python pypy3-test-instrumentation-kafka-python + lint-instrumentation-kafka-python ; opentelemetry-instrumentation-confluent-kafka py3{8,9,10,11}-test-instrumentation-confluent-kafka pypy3-test-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka ; opentelemetry-instrumentation-asyncio py3{8,9,10,11}-test-instrumentation-asyncio + lint-instrumentation-asyncio ; opentelemetry-instrumentation-cassandra py3{8,9,10,11}-test-instrumentation-cassandra pypy3-test-instrumentation-cassandra + lint-instrumentation-cassandra ; opentelemetry-processor-baggage py3{8,9,10,11}-test-processor-baggage pypy3-test-processor-baggage + ; requires snappy headers to be available on the system + lint-processor-baggage - lint spellcheck docker-tests docs @@ -308,6 +368,7 @@ envlist = [testenv] deps = -c dev-requirements.txt + lint: -r dev-requirements.txt test: pytest test: pytest-benchmark coverage: pytest @@ -349,12 +410,14 @@ commands_pre = py3{8,9}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-0.txt py3{10,11}-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt pypy3-test-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt + lint-instrumentation-celery: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt sio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api sio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions sio-pika: pip install opentelemetry-sdk@{env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk sio-pika-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-0.txt sio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt + lint-instrumentation-sio-pika: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt aio-pika: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api aio-pika: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -363,6 +426,7 @@ commands_pre = aio-pika-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-1.txt aio-pika-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt aio-pika-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt + lint-instrumentation-aio-pika: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-3.txt kafka-python: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api kafka-python: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -418,6 +482,7 @@ commands_pre = falcon-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-0.txt falcon-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-1.txt falcon-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt + lint-instrumentation-falcon: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt flask: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api flask: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -426,6 +491,7 @@ commands_pre = flask-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-0.txt flask-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-1.txt flask-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt + lint-instrumentation-flask: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt urllib: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api urllib: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -439,6 +505,7 @@ commands_pre = urllib3: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils urllib3-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-0.txt urllib3-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt + lint-instrumentation-urllib3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt botocore: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api botocore: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -469,6 +536,7 @@ commands_pre = py3{10,11}-test-instrumentation-django-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt pypy3-test-instrumentation-django-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-0.txt pypy3-test-instrumentation-django-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-1.txt + lint-instrumentation-django: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt fastapi: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api fastapi: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -497,6 +565,7 @@ commands_pre = pymemcache-2: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-2.txt pymemcache-3: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-3.txt pymemcache-4: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt + lint-instrumentation-pymemcache: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt pymongo: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api pymongo: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -511,6 +580,7 @@ commands_pre = py3{8,9}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-0.txt py3{10,11}-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt pypy3-test-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt + lint-instrumentation-psycopg: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt psycopg2: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api psycopg2: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -638,6 +708,7 @@ commands_pre = sqlalchemy: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils sqlalchemy-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-0.txt sqlalchemy-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt + lint-instrumentation-sqlalchemy: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt elasticsearch: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api elasticsearch: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -645,6 +716,7 @@ commands_pre = elasticsearch: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils elasticsearch-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-0.txt elasticsearch-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt + lint-instrumentation-elasticsearch: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt asyncio: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api asyncio: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -658,6 +730,7 @@ commands_pre = httpx: pip install opentelemetry-test-utils@{env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils httpx-0: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-0.txt httpx-1: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt + lint-instrumentation-httpx: pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt sdk-extension-aws: pip install opentelemetry-api@{env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api sdk-extension-aws: pip install opentelemetry-semantic-conventions@{env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions @@ -696,63 +769,406 @@ commands_pre = commands = test-distro: pytest {toxinidir}/opentelemetry-distro/tests {posargs} + lint-distro: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/opentelemetry-distro + lint-distro: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/opentelemetry-distro + lint-distro: flake8 --config {toxinidir}/.flake8 {toxinidir}/opentelemetry-distro + lint-distro: pylint {toxinidir}/opentelemetry-distro/src/opentelemetry + lint-distro: pylint {toxinidir}/opentelemetry-distro/tests + test-opentelemetry-instrumentation: pytest {toxinidir}/opentelemetry-instrumentation/tests {posargs} + lint-opentelemetry-instrumentation: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: flake8 --config {toxinidir}/.flake8 {toxinidir}/opentelemetry-instrumentation + lint-opentelemetry-instrumentation: pylint {toxinidir}/opentelemetry-instrumentation/src/opentelemetry + lint-opentelemetry-instrumentation: pylint {toxinidir}/opentelemetry-instrumentation/tests + test-instrumentation-aiohttp-client: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests {posargs} + lint-instrumentation-aiohttp-client: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client + lint-instrumentation-aiohttp-client: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry + lint-instrumentation-aiohttp-client: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/tests + test-instrumentation-aiohttp-server: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests {posargs} + lint-instrumentation-aiohttp-server: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server + lint-instrumentation-aiohttp-server: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry + lint-instrumentation-aiohttp-server: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests + test-instrumentation-aiopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/tests {posargs} + lint-instrumentation-aiopg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg + lint-instrumentation-aiopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry + lint-instrumentation-aiopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/tests + test-instrumentation-asgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/tests {posargs} + lint-instrumentation-asgi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi + lint-instrumentation-asgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry + lint-instrumentation-asgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/tests + test-instrumentation-asyncpg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/tests {posargs} + lint-instrumentation-asyncpg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg + lint-instrumentation-asyncpg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry + lint-instrumentation-asyncpg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/tests + test-instrumentation-aws-lambda: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/tests {posargs} + lint-instrumentation-aws-lambda: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda + lint-instrumentation-aws-lambda: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry + lint-instrumentation-aws-lambda: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/tests + test-instrumentation-boto: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/tests {posargs} + lint-instrumentation-boto: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-boto + lint-instrumentation-boto: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry + lint-instrumentation-boto: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/tests + test-instrumentation-botocore: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/tests {posargs} + lint-instrumentation-botocore: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore + lint-instrumentation-botocore: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry + lint-instrumentation-botocore: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/tests + test-instrumentation-boto3sqs: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/tests {posargs} + lint-instrumentation-boto3sqs: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs + lint-instrumentation-boto3sqs: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry + lint-instrumentation-boto3sqs: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/tests + test-instrumentation-cassandra: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/tests {posargs} + lint-instrumentation-cassandra: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra + lint-instrumentation-cassandra: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/src/opentelemetry + lint-instrumentation-cassandra: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/tests + test-instrumentation-celery: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/tests {posargs} + lint-instrumentation-celery: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-celery + lint-instrumentation-celery: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry + lint-instrumentation-celery: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/tests + test-instrumentation-dbapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/tests {posargs} + lint-instrumentation-dbapi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi + lint-instrumentation-dbapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry + lint-instrumentation-dbapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/tests + test-instrumentation-django: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-django/tests {posargs} + lint-instrumentation-django: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-django + lint-instrumentation-django: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry + lint-instrumentation-django: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-django/tests + test-instrumentation-elasticsearch: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/tests {posargs} + lint-instrumentation-elasticsearch: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch + lint-instrumentation-elasticsearch: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry + lint-instrumentation-elasticsearch: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/tests + test-instrumentation-falcon: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/tests {posargs} + lint-instrumentation-falcon: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon + lint-instrumentation-falcon: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry + lint-instrumentation-falcon: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/tests + test-instrumentation-fastapi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/tests {posargs} + lint-instrumentation-fastapi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi + lint-instrumentation-fastapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry + lint-instrumentation-fastapi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/tests + test-instrumentation-flask: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/tests {posargs} + lint-instrumentation-flask: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-flask + lint-instrumentation-flask: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry + lint-instrumentation-flask: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/tests + test-instrumentation-urllib: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/tests {posargs} + lint-instrumentation-urllib: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib + lint-instrumentation-urllib: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry + lint-instrumentation-urllib: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/tests + test-instrumentation-urllib3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/tests {posargs} + lint-instrumentation-urllib3: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3 + lint-instrumentation-urllib3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry + lint-instrumentation-urllib3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/tests + test-instrumentation-grpc: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/tests {posargs} + lint-instrumentation-grpc: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc + lint-instrumentation-grpc: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry + lint-instrumentation-grpc: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/tests + test-instrumentation-jinja2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/tests {posargs} + lint-instrumentation-jinja2: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2 + lint-instrumentation-jinja2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry + lint-instrumentation-jinja2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/tests + test-instrumentation-kafka-python: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/tests {posargs} + lint-instrumentation-kafka-python: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python + lint-instrumentation-kafka-python: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/src/opentelemetry + lint-instrumentation-kafka-python: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/tests + test-instrumentation-confluent-kafka: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/tests {posargs} + lint-instrumentation-confluent-kafka: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka + lint-instrumentation-confluent-kafka: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry + lint-instrumentation-confluent-kafka: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/tests + test-instrumentation-logging: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/tests {posargs} + lint-instrumentation-logging: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-logging + lint-instrumentation-logging: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry + lint-instrumentation-logging: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/tests + test-instrumentation-mysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/tests {posargs} + lint-instrumentation-mysql: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql + lint-instrumentation-mysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry + lint-instrumentation-mysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/tests + test-instrumentation-mysqlclient: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/tests {posargs} + lint-instrumentation-mysqlclient: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient + lint-instrumentation-mysqlclient: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/src/opentelemetry + lint-instrumentation-mysqlclient: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/tests + test-instrumentation-sio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/tests {posargs} + lint-instrumentation-sio-pika: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pika + lint-instrumentation-sio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry + lint-instrumentation-sio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/tests + test-instrumentation-aio-pika: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/tests {posargs} + lint-instrumentation-aio-pika: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika + lint-instrumentation-aio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry + lint-instrumentation-aio-pika: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/tests + test-instrumentation-psycopg: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/tests {posargs} + lint-instrumentation-psycopg: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg + lint-instrumentation-psycopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry + lint-instrumentation-psycopg: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/tests + test-instrumentation-psycopg2: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/tests {posargs} + lint-instrumentation-psycopg2: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2 + lint-instrumentation-psycopg2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry + lint-instrumentation-psycopg2: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/tests + test-instrumentation-pymemcache: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/tests {posargs} + lint-instrumentation-pymemcache: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache + lint-instrumentation-pymemcache: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry + lint-instrumentation-pymemcache: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/tests + test-instrumentation-pymongo: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/tests {posargs} + lint-instrumentation-pymongo: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo + lint-instrumentation-pymongo: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry + lint-instrumentation-pymongo: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/tests + test-instrumentation-pymysql: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/tests {posargs} + lint-instrumentation-pymysql: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql + lint-instrumentation-pymysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/src/opentelemetry + lint-instrumentation-pymysql: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/tests + test-instrumentation-pyramid: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/tests {posargs} + lint-instrumentation-pyramid: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid + lint-instrumentation-pyramid: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry + lint-instrumentation-pyramid: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/tests + test-instrumentation-redis: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/tests {posargs} + lint-instrumentation-redis: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-redis + lint-instrumentation-redis: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry + lint-instrumentation-redis: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/tests + test-instrumentation-remoulade: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/tests {posargs} + lint-instrumentation-remoulade: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade + lint-instrumentation-remoulade: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry + lint-instrumentation-remoulade: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/tests + test-instrumentation-requests: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/tests {posargs} + lint-instrumentation-requests: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-requests + lint-instrumentation-requests: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry + lint-instrumentation-requests: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/tests + test-instrumentation-sklearn: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/tests {posargs} + lint-instrumentation-sklearn: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn + lint-instrumentation-sklearn: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/src/opentelemetry + lint-instrumentation-sklearn: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/tests + test-instrumentation-sqlalchemy: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests {posargs} + lint-instrumentation-sqlalchemy: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy + lint-instrumentation-sqlalchemy: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry + lint-instrumentation-sqlalchemy: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests + test-instrumentation-sqlite3: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/tests {posargs} + lint-instrumentation-sqlite3: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3 + lint-instrumentation-sqlite3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry + lint-instrumentation-sqlite3: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/tests + test-instrumentation-starlette: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/tests {posargs} + lint-instrumentation-starlette: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette + lint-instrumentation-starlette: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry + lint-instrumentation-starlette: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/tests + test-instrumentation-system-metrics: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/tests {posargs} + lint-instrumentation-system-metrics: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics + lint-instrumentation-system-metrics: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry + lint-instrumentation-system-metrics: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/tests + test-instrumentation-threading: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/tests {posargs} + lint-instrumentation-threading: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-threading + lint-instrumentation-threading: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/src/opentelemetry + lint-instrumentation-threading: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/tests + test-instrumentation-tornado: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/tests {posargs} + lint-instrumentation-tornado: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado + lint-instrumentation-tornado: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry + lint-instrumentation-tornado: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/tests + test-instrumentation-tortoiseorm: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/tests {posargs} + lint-instrumentation-tortoiseorm: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm + lint-instrumentation-tortoiseorm: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry + lint-instrumentation-tortoiseorm: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/tests + test-instrumentation-wsgi: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/tests {posargs} + lint-instrumentation-wsgi: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi + lint-instrumentation-wsgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry + lint-instrumentation-wsgi: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/tests + test-instrumentation-httpx: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/tests {posargs} + lint-instrumentation-httpx: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx + lint-instrumentation-httpx: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry + lint-instrumentation-httpx: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/tests + test-instrumentation-asyncio: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/tests {posargs} + lint-instrumentation-asyncio: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: flake8 --config {toxinidir}/.flake8 {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio + lint-instrumentation-asyncio: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry + lint-instrumentation-asyncio: pylint {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/tests + test-util-http: pytest {toxinidir}/util/opentelemetry-util-http/tests {posargs} + test-sdk-extension-aws: pytest {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests {posargs} + lint-sdk-extension-aws: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: flake8 --config {toxinidir}/.flake8 {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws + lint-sdk-extension-aws: pylint {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry + lint-sdk-extension-aws: pylint {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/tests + test-resource-detector-container: pytest {toxinidir}/resource/opentelemetry-resource-detector-container/tests {posargs} + lint-resource-detector-container: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: flake8 --config {toxinidir}/.flake8 {toxinidir}/resource/opentelemetry-resource-detector-container + lint-resource-detector-container: pylint {toxinidir}/resource/opentelemetry-resource-detector-container/src/opentelemetry + lint-resource-detector-container: pylint {toxinidir}/resource/opentelemetry-resource-detector-container/tests + test-processor-baggage: pytest {toxinidir}/processor/opentelemetry-processor-baggage/tests {posargs} - test-propagator-aws: pytest {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests {posargs} + lint-processor-baggage: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: flake8 --config {toxinidir}/.flake8 {toxinidir}/processor/opentelemetry-processor-baggage + lint-processor-baggage: pylint {toxinidir}/processor/opentelemetry-processor-baggage/src/opentelemetry + lint-processor-baggage: pylint {toxinidir}/processor/opentelemetry-processor-baggage/tests + + test-propagator-aws-xray: pytest {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests {posargs} + lint-propagator-aws-xray: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: flake8 --config {toxinidir}/.flake8 {toxinidir}/propagator/opentelemetry-propagator-aws-xray + lint-propagator-aws-xray: pylint {toxinidir}/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry + lint-propagator-aws-xray: pylint {toxinidir}/propagator/opentelemetry-propagator-aws-xray/tests + test-propagator-ot-trace: pytest {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests {posargs} + lint-propagator-ot-trace: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: flake8 --config {toxinidir}/.flake8 {toxinidir}/propagator/opentelemetry-propagator-ot-trace + lint-propagator-ot-trace: pylint {toxinidir}/propagator/opentelemetry-propagator-ot-trace/src/opentelemetry + lint-propagator-ot-trace: pylint {toxinidir}/propagator/opentelemetry-propagator-ot-trace/tests + test-exporter-richconsole: pytest {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests {posargs} + lint-exporter-richconsole: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: flake8 --config {toxinidir}/.flake8 {toxinidir}/exporter/opentelemetry-exporter-richconsole + lint-exporter-richconsole: pylint {toxinidir}/exporter/opentelemetry-exporter-richconsole/src/opentelemetry + lint-exporter-richconsole: pylint {toxinidir}/exporter/opentelemetry-exporter-richconsole/tests + test-exporter-prometheus-remote-write: pytest {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests {posargs} + lint-exporter-prometheus-remote-write: black --diff --check --config {toxinidir}/pyproject.toml {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: isort --diff --check-only --settings-path {toxinidir}/.isort.cfg {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: flake8 --config {toxinidir}/.flake8 {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write + lint-exporter-prometheus-remote-write: pylint {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry + lint-exporter-prometheus-remote-write: pylint {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests + coverage: {toxinidir}/scripts/coverage.sh [testenv:docs] @@ -782,81 +1198,6 @@ deps = commands = codespell -[testenv:lint] -basepython: python3 -recreate = True -deps = - -r dev-requirements.txt - -commands_pre = - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-api&subdirectory=opentelemetry-api - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-semantic-conventions&subdirectory=opentelemetry-semantic-conventions - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-sdk&subdirectory=opentelemetry-sdk - python -m pip install {env:CORE_REPO}\#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils - python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test] - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore/test-requirements.txt - pip install -r {toxinidir}/opentelemetry-instrumentation/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-django/test-requirements-3.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon/test-requirements-2.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-flask/test-requirements-2.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-celery/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika/test-requirements-2.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-redis/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade/test-requirements.txt - ; pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache/test-requirements-4.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-logging/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-requests/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pika/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql/test-requirements.txt - # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install - # for your OS to install the required dependencies - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx/test-requirements-1.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio/test-requirements.txt - pip install -r {toxinidir}/exporter/opentelemetry-exporter-richconsole/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-threading/test-requirements.txt - pip install -r {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm/test-requirements.txt - # requires snappy headers to be available on the system - pip install -r {toxinidir}/resource/opentelemetry-resource-detector-container/test-requirements.txt - pip install -r {toxinidir}/processor/opentelemetry-processor-baggage/test-requirements.txt - pip install -r {toxinidir}/propagator/opentelemetry-propagator-aws-xray/test-requirements.txt - pip install -r {toxinidir}/propagator/opentelemetry-propagator-ot-trace/test-requirements.txt - pip install -r {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws/test-requirements.txt - pip install -r {toxinidir}/opentelemetry-distro/test-requirements.txt - -commands = - python scripts/eachdist.py lint --check-only - [testenv:docker-tests] basepython: python3 deps =