From 8d0c5042738ff916cb7bafc0af8eee7d258382fa Mon Sep 17 00:00:00 2001 From: Daniel Manchon Date: Sat, 26 Feb 2022 09:53:53 +0100 Subject: [PATCH 01/35] draft instrumentation for aiohttp server / guillotina --- .../README.rst | 24 +++ .../setup.cfg | 58 ++++++ .../setup.py | 89 ++++++++ .../aiohttp_server/__init__.py | 191 ++++++++++++++++++ .../instrumentation/aiohttp_server/package.py | 16 ++ .../instrumentation/aiohttp_server/version.py | 15 ++ .../tests/__init__.py | 0 7 files changed, 393 insertions(+) create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/README.rst create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/__init__.py diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/README.rst b/instrumentation/opentelemetry-instrumentation-aiohttp-server/README.rst new file mode 100644 index 0000000000..b8606ad687 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/README.rst @@ -0,0 +1,24 @@ +OpenTelemetry aiohttp server Integration +======================================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-aiohttp-client.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-aiohttp-client/ + +This library allows tracing HTTP requests made by the +`aiohttp server `_ library. + +Installation +------------ + +:: + + pip install opentelemetry-instrumentation-aiohttp-server + +References +---------- + +* `OpenTelemetry Project `_ +* `aiohttp client Tracing `_ +* `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg new file mode 100644 index 0000000000..1d32ab88ac --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg @@ -0,0 +1,58 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +[metadata] +name = opentelemetry-instrumentation-aiohttp-server +description = Aiohttp server instrumentation for OpenTelemetry +long_description = file: README.rst +long_description_content_type = text/x-rst +author = OpenTelemetry Authors +author_email = cncf-opentelemetry-contributors@lists.cncf.io +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aiohttp-server +platforms = any +license = Apache-2.0 +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.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + +[options] +python_requires = >=3.6 +package_dir= + =src +packages=find_namespace: +install_requires = + opentelemetry-api ~= 1.3 + opentelemetry-semantic-conventions == 0.28b1 + opentelemetry-instrumentation == 0.28b1 + opentelemetry-util-http == 0.28b1 + +[options.packages.find] +where = src + +[options.extras_require] +test = + opentelemetry-test-utils == 0.28b1 + + +[options.entry_points] +opentelemetry_instrumentor = + aiohttp-server = opentelemetry.instrumentation.aiohttp_server:AioHttpInstrumentor \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py new file mode 100644 index 0000000000..9a0f8ee641 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.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. + + +# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM templates/instrumentation_setup.py.txt. +# RUN `python scripts/generate_setup.py` TO REGENERATE. + + +import distutils.cmd +import json +import os +from configparser import ConfigParser + +import setuptools + +config = ConfigParser() +config.read("setup.cfg") + +# We provide extras_require parameter to setuptools.setup later which +# overwrites the extra_require section from setup.cfg. To support extra_require +# secion in setup.cfg, we load it here and merge it with the extra_require param. +extras_require = {} +if "options.extras_require" in config: + for key, value in config["options.extras_require"].items(): + extras_require[key] = [v for v in value.split("\n") if v.strip()] + +BASE_DIR = os.path.dirname(__file__) +PACKAGE_INFO = {} + +VERSION_FILENAME = os.path.join( + BASE_DIR, "src", "opentelemetry", "instrumentation", "aiohttp_server", "version.py" +) +with open(VERSION_FILENAME, encoding="utf-8") as f: + exec(f.read(), PACKAGE_INFO) + +PACKAGE_FILENAME = os.path.join( + BASE_DIR, "src", "opentelemetry", "instrumentation", "aiohttp_server", "package.py" +) +with open(PACKAGE_FILENAME, encoding="utf-8") as f: + exec(f.read(), PACKAGE_INFO) + +# Mark any instruments/runtime dependencies as test dependencies as well. +extras_require["instruments"] = PACKAGE_INFO["_instruments"] +test_deps = extras_require.get("test", []) +for dep in extras_require["instruments"]: + test_deps.append(dep) + +extras_require["test"] = test_deps + + +class JSONMetadataCommand(distutils.cmd.Command): + + description = ( + "print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ", + "auto-generate code in other places", + ) + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + metadata = { + "name": config["metadata"]["name"], + "version": PACKAGE_INFO["__version__"], + "instruments": PACKAGE_INFO["_instruments"], + } + print(json.dumps(metadata)) + + +setuptools.setup( + cmdclass={"meta": JSONMetadataCommand}, + version=PACKAGE_INFO["__version__"], + extras_require=extras_require, +) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py new file mode 100644 index 0000000000..9b5f83be2f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -0,0 +1,191 @@ +import urllib +from aiohttp import web +from guillotina.utils import get_dotted_name +from multidict import CIMultiDictProxy +from opentelemetry import context, trace +from opentelemetry.instrumentation.aiohttp_server.package import _instruments +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import http_status_to_status_code +from opentelemetry.propagate import extract +from opentelemetry.propagators.textmap import Getter +from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace.status import Status, StatusCode +from opentelemetry.util.http import get_excluded_urls +from opentelemetry.util.http import remove_url_credentials + +from typing import Tuple + + +_SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation" + +tracer = trace.get_tracer(__name__) +_excluded_urls = get_excluded_urls("FLASK") + + +def get_default_span_details(request: web.Request) -> Tuple[str, dict]: + """Default implementation for get_default_span_details + Args: + scope: the asgi scope dictionary + Returns: + a tuple of the span name, and any attributes to attach to the span. + """ + span_name = request.path.strip() or f"HTTP {request.method}" + return span_name, {} + + +def _get_view_func(request) -> str: + """TODO: is this only working for guillotina?""" + try: + return get_dotted_name(request.found_view) + except AttributeError: + return "unknown" + + +def collect_request_attributes(request: web.Request): + """Collects HTTP request attributes from the ASGI scope and returns a + dictionary to be used as span creation attributes.""" + + server_host, port, http_url = ( + request.url.host, + request.url.port, + str(request.url), + ) + query_string = request.query_string + if query_string and http_url: + if isinstance(query_string, bytes): + query_string = query_string.decode("utf8") + http_url += "?" + urllib.parse.unquote(query_string) + + result = { + SpanAttributes.HTTP_SCHEME: request.scheme, + SpanAttributes.HTTP_HOST: server_host, + SpanAttributes.NET_HOST_PORT: port, + SpanAttributes.HTTP_ROUTE: _get_view_func(request), + SpanAttributes.HTTP_FLAVOR: f"{request.version.major}.{request.version.minor}", + SpanAttributes.HTTP_TARGET: request.path, + SpanAttributes.HTTP_URL: remove_url_credentials(http_url), + } + + http_method = request.method + if http_method: + result[SpanAttributes.HTTP_METHOD] = http_method + + http_host_value_list = ( + [request.host] if type(request.host) != list else request.host + ) + if http_host_value_list: + result[SpanAttributes.HTTP_SERVER_NAME] = ",".join( + http_host_value_list + ) + http_user_agent = request.headers.get("user-agent") + if http_user_agent: + result[SpanAttributes.HTTP_USER_AGENT] = http_user_agent + + # remove None values + result = {k: v for k, v in result.items() if v is not None} + + return result + + +def set_status_code(span, status_code): + """Adds HTTP response attributes to span using the status_code argument.""" + if not span.is_recording(): + return + try: + status_code = int(status_code) + 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)) + ) + + +class AiohttpGetter(Getter): + """Extract current trace from headers""" + + def get(self, carrier, key: str): + """Getter implementation to retrieve a HTTP header value from the ASGI + scope. + + Args: + carrier: ASGI scope object + key: header name in scope + Returns: + A list with a single string with the header value if it exists, + else None. + """ + headers: CIMultiDictProxy = carrier.headers + if not headers: + return None + return headers.getall(key, None) + + def keys(self, carrier: dict): + return list(carrier.keys()) + + +getter = AiohttpGetter() + + +@web.middleware +async def middleware(request, handler): + """Middleware for aiohttp implementing tracing logic""" + if ( + context.get_value("suppress_instrumentation") + or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY) + or not _excluded_urls.url_disabled(request.url) + ): + return await handler(request) + + token = context.attach(extract(request, getter=getter)) + span_name, additional_attributes = get_default_span_details(request) + + with tracer.start_as_current_span( + span_name, + kind=trace.SpanKind.SERVER, + ) as span: + if span.is_recording(): + attributes = collect_request_attributes(request) + attributes.update(additional_attributes) + for key, value in attributes.items(): + span.set_attribute(key, value) + try: + resp = await handler(request) + set_status_code(span, resp.status) + finally: + context.detach(token) + return resp + + +class _InstrumentedApplication(web.Application): + """Insert tracing middleware""" + + def __init__(self, *args, **kwargs): + middlewares = kwargs.pop("middlewares", []) + middlewares.insert(0, middleware) + kwargs["middlewares"] = middlewares + super().__init__(*args, **kwargs) + + +class AioHttpInstrumentor(BaseInstrumentor): + # pylint: disable=protected-access,attribute-defined-outside-init + """An instrumentor for aiohttp.web.Application + + See `BaseInstrumentor` + """ + + def _instrument(self, **kwargs): + self._original_app = web.Application + setattr(web, "Application", _InstrumentedApplication) + + def _uninstrument(self, **kwargs): + setattr(web, "Application", self._original_app) + + def instrumentation_dependencies(self): + return _instruments diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py new file mode 100644 index 0000000000..bd7c16572a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py @@ -0,0 +1,16 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +_instruments = ("aiohttp ~= 3.8",) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py new file mode 100644 index 0000000000..a94d4ed446 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/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.28b1" diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 5a14c7dae9a2908d0d064cf90bed7b3a234026ef Mon Sep 17 00:00:00 2001 From: Daniel Manchon Date: Wed, 2 Mar 2022 23:04:41 +0100 Subject: [PATCH 02/35] aiohttp server --- .../setup.cfg | 2 +- .../aiohttp_server/__init__.py | 11 +- .../tests/test_aiohttp_server_integration.py | 133 ++++++++++++++++++ .../instrumentation/bootstrap.py | 12 +- .../instrumentation/bootstrap_gen.py | 5 +- tox.ini | 8 ++ 6 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg index 1d32ab88ac..a5def2a8cc 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg @@ -55,4 +55,4 @@ test = [options.entry_points] opentelemetry_instrumentor = - aiohttp-server = opentelemetry.instrumentation.aiohttp_server:AioHttpInstrumentor \ No newline at end of file + aiohttp-server = opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 9b5f83be2f..b9cd548420 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -1,6 +1,5 @@ import urllib from aiohttp import web -from guillotina.utils import get_dotted_name from multidict import CIMultiDictProxy from opentelemetry import context, trace from opentelemetry.instrumentation.aiohttp_server.package import _instruments @@ -19,7 +18,7 @@ _SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation" tracer = trace.get_tracer(__name__) -_excluded_urls = get_excluded_urls("FLASK") +_excluded_urls = get_excluded_urls("AIOHTTP_SERVER") def get_default_span_details(request: web.Request) -> Tuple[str, dict]: @@ -34,9 +33,9 @@ def get_default_span_details(request: web.Request) -> Tuple[str, dict]: def _get_view_func(request) -> str: - """TODO: is this only working for guillotina?""" + """TODO: is this useful??""" try: - return get_dotted_name(request.found_view) + return request.match_info.handler.__name__ except AttributeError: return "unknown" @@ -139,7 +138,7 @@ async def middleware(request, handler): if ( context.get_value("suppress_instrumentation") or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY) - or not _excluded_urls.url_disabled(request.url) + or _excluded_urls.url_disabled(request.url) ): return await handler(request) @@ -173,7 +172,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) -class AioHttpInstrumentor(BaseInstrumentor): +class AioHttpServerInstrumentor(BaseInstrumentor): # pylint: disable=protected-access,attribute-defined-outside-init """An instrumentor for aiohttp.web.Application diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py new file mode 100644 index 0000000000..f029f0e954 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -0,0 +1,133 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +import contextlib +import typing +import unittest +import urllib.parse +from functools import partial +from http import HTTPStatus +from unittest import mock + +import aiohttp +import aiohttp.test_utils +import yarl +from pkg_resources import iter_entry_points + +from opentelemetry import context +from opentelemetry.instrumentation import aiohttp_server +from opentelemetry.instrumentation.aiohttp_server import ( + AioHttpServerInstrumentor, +) +from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY +from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import Span, StatusCode + + +def run_with_test_server( + runnable: typing.Callable, url: str, handler: typing.Callable +) -> typing.Tuple[str, int]: + async def do_request(): + app = aiohttp.web.Application() + parsed_url = urllib.parse.urlparse(url) + app.add_routes([aiohttp.web.get(parsed_url.path, handler)]) + app.add_routes([aiohttp.web.post(parsed_url.path, handler)]) + app.add_routes([aiohttp.web.patch(parsed_url.path, handler)]) + + with contextlib.suppress(aiohttp.ClientError): + async with aiohttp.test_utils.TestServer(app) as server: + netloc = (server.host, server.port) + await server.start_server() + await runnable(server) + return netloc + + loop = asyncio.get_event_loop() + return loop.run_until_complete(do_request()) + + +class TestAioHttpServerIntegration(TestBase): + URL = "/test-path" + + def setUp(self): + super().setUp() + AioHttpServerInstrumentor().instrument() + + def tearDown(self): + super().tearDown() + AioHttpServerInstrumentor().uninstrument() + + @staticmethod + # pylint:disable=unused-argument + async def default_handler(request, status=200): + return aiohttp.web.Response(status=status) + + def assert_spans(self, num_spans: int): + finished_spans = self.memory_exporter.get_finished_spans() + self.assertEqual(num_spans, len(finished_spans)) + if num_spans == 0: + return None + if num_spans == 1: + return finished_spans[0] + return finished_spans + + @staticmethod + def get_default_request(url: str = URL): + async def default_request(server: aiohttp.test_utils.TestServer): + async with aiohttp.test_utils.TestClient(server) as session: + await session.get(url) + + return default_request + + def test_instrument(self): + host, port = run_with_test_server( + self.get_default_request(), self.URL, self.default_handler + ) + span = self.assert_spans(1) + self.assertEqual("GET", span.attributes[SpanAttributes.HTTP_METHOD]) + self.assertEqual( + f"http://{host}:{port}/test-path", + span.attributes[SpanAttributes.HTTP_URL], + ) + self.assertEqual(200, span.attributes[SpanAttributes.HTTP_STATUS_CODE]) + + def test_status_codes(self): + error_handler = partial(self.default_handler, status=400) + host, port = run_with_test_server( + self.get_default_request(), self.URL, error_handler + ) + span = self.assert_spans(1) + self.assertEqual("GET", span.attributes[SpanAttributes.HTTP_METHOD]) + self.assertEqual( + f"http://{host}:{port}/test-path", + span.attributes[SpanAttributes.HTTP_URL], + ) + self.assertEqual(400, span.attributes[SpanAttributes.HTTP_STATUS_CODE]) + + def test_not_recording(self): + 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"): + # pylint: disable=W0612 + host, port = run_with_test_server( + self.get_default_request(), self.URL, self.default_handler + ) + + self.assertFalse(mock_span.is_recording()) + self.assertTrue(mock_span.is_recording.called) + self.assertFalse(mock_span.set_attribute.called) + self.assertFalse(mock_span.set_status.called) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py index 6fa36f0463..bb0044850a 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py @@ -103,13 +103,11 @@ def _is_installed(req): def _find_installed_libraries(): libs = default_instrumentations[:] - libs.extend( - [ - v["instrumentation"] - for _, v in libraries.items() - if _is_installed(v["library"]) - ] - ) + + for _, v in libraries.items(): + if _is_installed(v["library"]): + libs.extend(v["instrumentation"]) + return libs diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 05c77b9fea..674c012e84 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -22,7 +22,10 @@ }, "aiohttp": { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.39b0.dev", + "instrumentation": [ + "opentelemetry-instrumentation-aiohttp-client==0.39b0.dev", + "opentelemetry-instrumentation-aiohttp-server==0.39b0.dev", + ], }, "aiopg": { "library": "aiopg >= 0.13.0, < 2.0.0", diff --git a/tox.ini b/tox.ini index 1603dfb745..b3a542ab30 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,10 @@ envlist = py3{7,8,9,10,11}-test-instrumentation-aiohttp-client pypy3-test-instrumentation-aiohttp-client + ; opentelemetry-instrumentation-aiohttp-server + py3{6,7,8,9,10}-test-instrumentation-aiohttp-server + pypy3-test-instrumentation-aiohttp-server + ; opentelemetry-instrumentation-aiopg py3{7,8,9,10,11}-test-instrumentation-aiopg ; instrumentation-aiopg intentionally excluded from pypy3 @@ -287,6 +291,7 @@ changedir = test-opentelemetry-instrumentation: opentelemetry-instrumentation/tests test-instrumentation-aio-pika: instrumentation/opentelemetry-instrumentation-aio-pika/tests test-instrumentation-aiohttp-client: instrumentation/opentelemetry-instrumentation-aiohttp-client/tests + test-instrumentation-aiohttp-server: instrumentation/opentelemetry-instrumentation-aiohttp-server/tests test-instrumentation-aiopg: instrumentation/opentelemetry-instrumentation-aiopg/tests test-instrumentation-asgi: instrumentation/opentelemetry-instrumentation-asgi/tests test-instrumentation-asyncpg: instrumentation/opentelemetry-instrumentation-asyncpg/tests @@ -425,6 +430,8 @@ commands_pre = aiohttp-client: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] + aiohttp-server: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] + aiopg: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] richconsole: pip install flaky {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] @@ -527,6 +534,7 @@ commands_pre = python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] From 57f59b07b2d1f21664af7bb57b4e16df9219f5c7 Mon Sep 17 00:00:00 2001 From: Daniel Manchon Date: Thu, 3 Mar 2022 08:34:12 +0100 Subject: [PATCH 03/35] aiohttp server tests --- .../tests/test_aiohttp_server_integration.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index f029f0e954..3139861401 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -18,23 +18,15 @@ import unittest import urllib.parse from functools import partial -from http import HTTPStatus from unittest import mock import aiohttp import aiohttp.test_utils -import yarl from pkg_resources import iter_entry_points -from opentelemetry import context -from opentelemetry.instrumentation import aiohttp_server -from opentelemetry.instrumentation.aiohttp_server import ( - AioHttpServerInstrumentor, -) -from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY +from opentelemetry.instrumentation.aiohttp_server import AioHttpServerInstrumentor from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.test.test_base import TestBase -from opentelemetry.trace import Span, StatusCode def run_with_test_server( @@ -131,3 +123,13 @@ def test_not_recording(self): self.assertTrue(mock_span.is_recording.called) self.assertFalse(mock_span.set_attribute.called) self.assertFalse(mock_span.set_status.called) + + +class TestLoadingAioHttpInstrumentor(unittest.TestCase): + def test_loading_instrumentor(self): + entry_points = iter_entry_points( + "opentelemetry_instrumentor", "aiohttp-server" + ) + + instrumentor = next(entry_points).load()() + self.assertIsInstance(instrumentor, AioHttpServerInstrumentor) From ceb0d18ac3bcba95f8bbc195713f87d8edf4ad9f Mon Sep 17 00:00:00 2001 From: Daniel Manchon Date: Sun, 19 Feb 2023 14:20:11 +0100 Subject: [PATCH 04/35] PR comments --- .../setup.cfg | 10 +++++----- .../aiohttp_server/__init__.py | 20 +++++++------------ .../instrumentation/aiohttp_server/version.py | 2 +- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg index a5def2a8cc..bdd3dcee19 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg @@ -40,17 +40,17 @@ package_dir= =src packages=find_namespace: install_requires = - opentelemetry-api ~= 1.3 - opentelemetry-semantic-conventions == 0.28b1 - opentelemetry-instrumentation == 0.28b1 - opentelemetry-util-http == 0.28b1 + opentelemetry-api ~= 1.12 + opentelemetry-semantic-conventions == 0.38b0.dev + opentelemetry-instrumentation == 0.38b0.dev + opentelemetry-util-http == 0.38b0.dev [options.packages.find] where = src [options.extras_require] test = - opentelemetry-test-utils == 0.28b1 + opentelemetry-test-utils == 0.38b0.dev [options.entry_points] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index b9cd548420..c839f55b0a 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -138,28 +138,22 @@ async def middleware(request, handler): if ( context.get_value("suppress_instrumentation") or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY) - or _excluded_urls.url_disabled(request.url) + or _excluded_urls.url_disabled(request.url.path) ): return await handler(request) - token = context.attach(extract(request, getter=getter)) span_name, additional_attributes = get_default_span_details(request) with tracer.start_as_current_span( span_name, kind=trace.SpanKind.SERVER, ) as span: - if span.is_recording(): - attributes = collect_request_attributes(request) - attributes.update(additional_attributes) - for key, value in attributes.items(): - span.set_attribute(key, value) - try: - resp = await handler(request) - set_status_code(span, resp.status) - finally: - context.detach(token) - return resp + attributes = collect_request_attributes(request) + attributes.update(additional_attributes) + span.setattributes(attributes) + resp = await handler(request) + set_status_code(span, resp.status) + return resp class _InstrumentedApplication(web.Application): diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index a94d4ed446..8778b43b17 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.28b1" +__version__ = "0.38b0.dev" From ea76c6d679b238e5d0a735b5e8d2e29f8fff7edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 12 Apr 2023 11:42:49 -0300 Subject: [PATCH 05/35] Change the project to use pyproject conventions and bump version --- .../pyproject.toml | 60 +++++++++++++ .../setup.cfg | 58 ------------ .../setup.py | 89 ------------------- .../instrumentation/aiohttp_server/version.py | 2 +- 4 files changed, 61 insertions(+), 148 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml delete mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg delete mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml new file mode 100644 index 0000000000..973a871db8 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -0,0 +1,60 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-instrumentation-aiohttp-server" +dynamic = ["version"] +description = "Aiohttp server instrumentation for OpenTelemetry" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.7" +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.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11" +] +dependencies = [ + "opentelemetry-api ~= 1.12", + "opentelemetry-instrumentation == 0.39b0.dev", + "opentelemetry-semantic-conventions == 0.39b0.dev", + "opentelemetry-util-http == 0.39b0.dev", + "wrapt >= 1.0.0, < 2.0.0", +] + +[project.optional-dependencies] +instruments = [ + "aiohttp ~= 3.0", +] +test = [ + "opentelemetry-instrumentation-aiohttp-server[instruments]", +] + +[project.entry-points.opentelemetry_instrumentor] +aiohttp-client = "opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor" + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aiohttp-server" + +[tool.hatch.version] +path = "src/opentelemetry/instrumentation/aiohttp_server/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg deleted file mode 100644 index bdd3dcee19..0000000000 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.cfg +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -[metadata] -name = opentelemetry-instrumentation-aiohttp-server -description = Aiohttp server instrumentation for OpenTelemetry -long_description = file: README.rst -long_description_content_type = text/x-rst -author = OpenTelemetry Authors -author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aiohttp-server -platforms = any -license = Apache-2.0 -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.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - -[options] -python_requires = >=3.6 -package_dir= - =src -packages=find_namespace: -install_requires = - opentelemetry-api ~= 1.12 - opentelemetry-semantic-conventions == 0.38b0.dev - opentelemetry-instrumentation == 0.38b0.dev - opentelemetry-util-http == 0.38b0.dev - -[options.packages.find] -where = src - -[options.extras_require] -test = - opentelemetry-test-utils == 0.38b0.dev - - -[options.entry_points] -opentelemetry_instrumentor = - aiohttp-server = opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py deleted file mode 100644 index 9a0f8ee641..0000000000 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/setup.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM templates/instrumentation_setup.py.txt. -# RUN `python scripts/generate_setup.py` TO REGENERATE. - - -import distutils.cmd -import json -import os -from configparser import ConfigParser - -import setuptools - -config = ConfigParser() -config.read("setup.cfg") - -# We provide extras_require parameter to setuptools.setup later which -# overwrites the extra_require section from setup.cfg. To support extra_require -# secion in setup.cfg, we load it here and merge it with the extra_require param. -extras_require = {} -if "options.extras_require" in config: - for key, value in config["options.extras_require"].items(): - extras_require[key] = [v for v in value.split("\n") if v.strip()] - -BASE_DIR = os.path.dirname(__file__) -PACKAGE_INFO = {} - -VERSION_FILENAME = os.path.join( - BASE_DIR, "src", "opentelemetry", "instrumentation", "aiohttp_server", "version.py" -) -with open(VERSION_FILENAME, encoding="utf-8") as f: - exec(f.read(), PACKAGE_INFO) - -PACKAGE_FILENAME = os.path.join( - BASE_DIR, "src", "opentelemetry", "instrumentation", "aiohttp_server", "package.py" -) -with open(PACKAGE_FILENAME, encoding="utf-8") as f: - exec(f.read(), PACKAGE_INFO) - -# Mark any instruments/runtime dependencies as test dependencies as well. -extras_require["instruments"] = PACKAGE_INFO["_instruments"] -test_deps = extras_require.get("test", []) -for dep in extras_require["instruments"]: - test_deps.append(dep) - -extras_require["test"] = test_deps - - -class JSONMetadataCommand(distutils.cmd.Command): - - description = ( - "print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ", - "auto-generate code in other places", - ) - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - metadata = { - "name": config["metadata"]["name"], - "version": PACKAGE_INFO["__version__"], - "instruments": PACKAGE_INFO["_instruments"], - } - print(json.dumps(metadata)) - - -setuptools.setup( - cmdclass={"meta": JSONMetadataCommand}, - version=PACKAGE_INFO["__version__"], - extras_require=extras_require, -) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index 8778b43b17..eb62a67e28 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.38b0.dev" +__version__ = "0.39b0.dev" From 1239fc588003f726984e7ee97229e44fced9ab37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 12 Apr 2023 12:22:28 -0300 Subject: [PATCH 06/35] Fixes the resource name in pyproject. --- .../opentelemetry-instrumentation-aiohttp-server/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 973a871db8..b66afda9d3 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -42,7 +42,7 @@ test = [ ] [project.entry-points.opentelemetry_instrumentor] -aiohttp-client = "opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor" +aiohttp-server = "opentelemetry.instrumentation.aiohttp_server:AioHttpServerInstrumentor" [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aiohttp-server" From 3c00ed7c569a51df82e9bd52d11d2b18a1a8eab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 12 Apr 2023 12:23:04 -0300 Subject: [PATCH 07/35] Reverts to the previous usage of set_attributes method. --- .../opentelemetry/instrumentation/aiohttp_server/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index c839f55b0a..1d5b2471ea 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -5,7 +5,6 @@ from opentelemetry.instrumentation.aiohttp_server.package import _instruments from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import http_status_to_status_code -from opentelemetry.propagate import extract from opentelemetry.propagators.textmap import Getter from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status, StatusCode @@ -150,7 +149,7 @@ async def middleware(request, handler): ) as span: attributes = collect_request_attributes(request) attributes.update(additional_attributes) - span.setattributes(attributes) + span.set_attributes(attributes) resp = await handler(request) set_status_code(span, resp.status) return resp From 767adcc92ea96996e1f95a840b74b68182e3cda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 14 Apr 2023 11:48:58 -0300 Subject: [PATCH 08/35] Add pytest-asyncio and pytest-aiohttp as test dependencies. --- .../opentelemetry-instrumentation-aiohttp-server/pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index b66afda9d3..05f1446f94 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -39,6 +39,8 @@ instruments = [ ] test = [ "opentelemetry-instrumentation-aiohttp-server[instruments]", + "pytest-asyncio", + "pytest-aiohttp", ] [project.entry-points.opentelemetry_instrumentor] From e312bec314dcca2850520115452ac03a88b8f712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 14 Apr 2023 11:53:57 -0300 Subject: [PATCH 09/35] Convert the unittest tests to pytest test style. --- .../tests/test_aiohttp_server_integration.py | 216 +++++++++--------- 1 file changed, 102 insertions(+), 114 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 3139861401..813f53c968 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -12,124 +12,112 @@ # See the License for the specific language governing permissions and # limitations under the License. -import asyncio -import contextlib -import typing -import unittest -import urllib.parse -from functools import partial -from unittest import mock - +import pytest +import pytest_asyncio import aiohttp -import aiohttp.test_utils +from http import HTTPMethod, HTTPStatus from pkg_resources import iter_entry_points +from unittest import mock +from opentelemetry import trace as trace_api +from opentelemetry.test.test_base import TestBase from opentelemetry.instrumentation.aiohttp_server import AioHttpServerInstrumentor from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.test.test_base import TestBase +from opentelemetry.test.globals_test import ( + reset_trace_globals, +) + + +@pytest.fixture(scope="session") +def tracer(): + test_base = TestBase() + + tracer_provider, memory_exporter = test_base.create_tracer_provider() + + reset_trace_globals() + trace_api.set_tracer_provider(tracer_provider) + + yield tracer_provider, memory_exporter + + reset_trace_globals() + + +async def default_handler(request, status=200): + return aiohttp.web.Response(status=status) + + +@pytest_asyncio.fixture +async def server_fixture(tracer, aiohttp_server): + _, memory_exporter = tracer + + AioHttpServerInstrumentor().instrument() + + app = aiohttp.web.Application() + app.add_routes( + [aiohttp.web.get("/test-path", default_handler)]) + + server = await aiohttp_server(app) + yield server, app + + memory_exporter.clear() + + AioHttpServerInstrumentor().uninstrument() + + +def test_checking_instrumentor_pkg_installed(): + entry_points = iter_entry_points( + "opentelemetry_instrumentor", "aiohttp-server" + ) + + instrumentor = next(entry_points).load()() + assert (isinstance(instrumentor, AioHttpServerInstrumentor)) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("url, expected_method, expected_status_code", [ + ("/test-path", HTTPMethod.GET, HTTPStatus.OK), + ("/not-found", HTTPMethod.GET, HTTPStatus.NOT_FOUND) +]) +async def test_status_code_instrumentation(tracer, server_fixture, + aiohttp_client, url, + expected_method, + expected_status_code): + _, memory_exporter = tracer + server, app = server_fixture + + assert len(memory_exporter.get_finished_spans()) == 0 + + client = await aiohttp_client(server) + await client.get(url) + + assert len(memory_exporter.get_finished_spans()) == 1 + + [span] = memory_exporter.get_finished_spans() + + assert expected_method == span.attributes[SpanAttributes.HTTP_METHOD] + assert expected_status_code == span.attributes[SpanAttributes.HTTP_STATUS_CODE] + + assert f"http://{server.host}:{server.port}{url}" == span.attributes[ + SpanAttributes.HTTP_URL + ] + + +@pytest.mark.skip(reason="Historical purposes. Can't see the reason of this mock.") +def test_not_recording(self): + 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 patched: + patched.start_span.return_value = mock_span + # pylint: disable=W0612 + # host, port = run_with_test_server( + # self.get_default_request(), self.URL, self.default_handler + # ) -def run_with_test_server( - runnable: typing.Callable, url: str, handler: typing.Callable -) -> typing.Tuple[str, int]: - async def do_request(): - app = aiohttp.web.Application() - parsed_url = urllib.parse.urlparse(url) - app.add_routes([aiohttp.web.get(parsed_url.path, handler)]) - app.add_routes([aiohttp.web.post(parsed_url.path, handler)]) - app.add_routes([aiohttp.web.patch(parsed_url.path, handler)]) - - with contextlib.suppress(aiohttp.ClientError): - async with aiohttp.test_utils.TestServer(app) as server: - netloc = (server.host, server.port) - await server.start_server() - await runnable(server) - return netloc - - loop = asyncio.get_event_loop() - return loop.run_until_complete(do_request()) - - -class TestAioHttpServerIntegration(TestBase): - URL = "/test-path" - - def setUp(self): - super().setUp() - AioHttpServerInstrumentor().instrument() - - def tearDown(self): - super().tearDown() - AioHttpServerInstrumentor().uninstrument() - - @staticmethod - # pylint:disable=unused-argument - async def default_handler(request, status=200): - return aiohttp.web.Response(status=status) - - def assert_spans(self, num_spans: int): - finished_spans = self.memory_exporter.get_finished_spans() - self.assertEqual(num_spans, len(finished_spans)) - if num_spans == 0: - return None - if num_spans == 1: - return finished_spans[0] - return finished_spans - - @staticmethod - def get_default_request(url: str = URL): - async def default_request(server: aiohttp.test_utils.TestServer): - async with aiohttp.test_utils.TestClient(server) as session: - await session.get(url) - - return default_request - - def test_instrument(self): - host, port = run_with_test_server( - self.get_default_request(), self.URL, self.default_handler - ) - span = self.assert_spans(1) - self.assertEqual("GET", span.attributes[SpanAttributes.HTTP_METHOD]) - self.assertEqual( - f"http://{host}:{port}/test-path", - span.attributes[SpanAttributes.HTTP_URL], - ) - self.assertEqual(200, span.attributes[SpanAttributes.HTTP_STATUS_CODE]) - - def test_status_codes(self): - error_handler = partial(self.default_handler, status=400) - host, port = run_with_test_server( - self.get_default_request(), self.URL, error_handler - ) - span = self.assert_spans(1) - self.assertEqual("GET", span.attributes[SpanAttributes.HTTP_METHOD]) - self.assertEqual( - f"http://{host}:{port}/test-path", - span.attributes[SpanAttributes.HTTP_URL], - ) - self.assertEqual(400, span.attributes[SpanAttributes.HTTP_STATUS_CODE]) - - def test_not_recording(self): - 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"): - # pylint: disable=W0612 - host, port = run_with_test_server( - self.get_default_request(), self.URL, self.default_handler - ) - - self.assertFalse(mock_span.is_recording()) - self.assertTrue(mock_span.is_recording.called) - self.assertFalse(mock_span.set_attribute.called) - self.assertFalse(mock_span.set_status.called) - - -class TestLoadingAioHttpInstrumentor(unittest.TestCase): - def test_loading_instrumentor(self): - entry_points = iter_entry_points( - "opentelemetry_instrumentor", "aiohttp-server" - ) - - instrumentor = next(entry_points).load()() - self.assertIsInstance(instrumentor, AioHttpServerInstrumentor) + self.assertTrue(patched.start_span.called) + self.assertFalse(mock_span.is_recording()) + self.assertTrue(mock_span.is_recording.called) + self.assertFalse(mock_span.set_attribute.called) + self.assertFalse(mock_span.set_status.called) From 8699f9cbefd669173190af26b50493e0a14717c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 14 Apr 2023 11:55:17 -0300 Subject: [PATCH 10/35] Deal with an exception not setting the span's http status code. --- .../instrumentation/aiohttp_server/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 1d5b2471ea..dbdfad57dc 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -150,8 +150,12 @@ async def middleware(request, handler): attributes = collect_request_attributes(request) attributes.update(additional_attributes) span.set_attributes(attributes) - resp = await handler(request) - set_status_code(span, resp.status) + try: + resp = await handler(request) + set_status_code(span, resp.status) + except web.HTTPException as ex: + set_status_code(span, ex.status_code) + raise return resp From c29be3079d2829e0ae00cb94d355362b67bf0224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 14 Apr 2023 14:41:47 -0300 Subject: [PATCH 11/35] Remove Python 3.6 as supported version. --- .../opentelemetry-instrumentation-aiohttp-server/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 05f1446f94..8596a9c425 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -18,7 +18,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", From ad6b87ff8f2555b5494215caf3e473d952e4f9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 14 Apr 2023 14:42:46 -0300 Subject: [PATCH 12/35] Add the new aiohttp-server package as project dependency. --- opentelemetry-contrib-instrumentations/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index d05a7712ad..5d50b6d81f 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -31,6 +31,7 @@ classifiers = [ dependencies = [ "opentelemetry-instrumentation-aio-pika==0.39b0.dev", "opentelemetry-instrumentation-aiohttp-client==0.39b0.dev", + "opentelemetry-instrumentation-aiohttp-server==0.39b0.dev", "opentelemetry-instrumentation-aiopg==0.39b0.dev", "opentelemetry-instrumentation-asgi==0.39b0.dev", "opentelemetry-instrumentation-asyncpg==0.39b0.dev", From b0063053d1b8cb3860ca9327621d7119c8dfc327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 10 May 2023 10:48:59 -0300 Subject: [PATCH 13/35] Adds Metric support. --- .../aiohttp_server/__init__.py | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index dbdfad57dc..aa2a87b047 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -1,12 +1,16 @@ import urllib from aiohttp import web from multidict import CIMultiDictProxy -from opentelemetry import context, trace +from timeit import default_timer + +from opentelemetry import context, trace, metrics from opentelemetry.instrumentation.aiohttp_server.package import _instruments +from opentelemetry.instrumentation.aiohttp_server.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import http_status_to_status_code from opentelemetry.propagators.textmap import Getter from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.semconv.metrics import MetricInstruments from opentelemetry.trace.status import Status, StatusCode from opentelemetry.util.http import get_excluded_urls from opentelemetry.util.http import remove_url_credentials @@ -16,10 +20,47 @@ _SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation" +_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, + SpanAttributes.HTTP_ROUTE, +] + +_active_requests_count_attrs = [ + SpanAttributes.HTTP_METHOD, + SpanAttributes.HTTP_HOST, + SpanAttributes.HTTP_SCHEME, + SpanAttributes.HTTP_FLAVOR, + SpanAttributes.HTTP_SERVER_NAME, +] + tracer = trace.get_tracer(__name__) +meter = metrics.get_meter(__name__, __version__) _excluded_urls = get_excluded_urls("AIOHTTP_SERVER") +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_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 get_default_span_details(request: web.Request) -> Tuple[str, dict]: """Default implementation for get_default_span_details Args: @@ -143,6 +184,22 @@ async def middleware(request, handler): span_name, additional_attributes = get_default_span_details(request) + req_attrs = collect_request_attributes(request) + duration_attrs = _parse_duration_attrs(req_attrs) + active_requests_count_attrs = _parse_active_request_count_attrs(req_attrs) + + duration_histogram = meter.create_histogram( + name=MetricInstruments.HTTP_SERVER_DURATION, + unit="ms", + 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 those are currently in flight", + ) + with tracer.start_as_current_span( span_name, kind=trace.SpanKind.SERVER, @@ -150,12 +207,18 @@ async def middleware(request, handler): attributes = collect_request_attributes(request) attributes.update(additional_attributes) span.set_attributes(attributes) + start = default_timer() + active_requests_counter.add(1, active_requests_count_attrs) try: resp = await handler(request) set_status_code(span, resp.status) except web.HTTPException as ex: set_status_code(span, ex.status_code) raise + finally: + duration = max(round((default_timer() - start) * 1000), 0) + duration_histogram.record(duration, duration_attrs) + active_requests_counter.add(-1, active_requests_count_attrs) return resp From be9ccfc0127776cebdf17126b3390b90df01230d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 10 May 2023 10:50:04 -0300 Subject: [PATCH 14/35] Refactor some tests. --- .../tests/test_aiohttp_server_integration.py | 3 ++- .../tests/utils.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 813f53c968..115759def7 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -15,7 +15,8 @@ import pytest import pytest_asyncio import aiohttp -from http import HTTPMethod, HTTPStatus +from http import HTTPStatus +from .utils import HTTPMethod from pkg_resources import iter_entry_points from unittest import mock diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py new file mode 100644 index 0000000000..bbe1ce49bd --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py @@ -0,0 +1,25 @@ +# This was adapted from Python 3.11 http module. +from enum import Enum + + +class HTTPMethod(Enum): + """HTTP methods and descriptions + + Methods from the following RFCs are all observed: + + * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 + * RFC 5789: PATCH Method for HTTP + """ + + def __repr__(self): + return self.value[0] + + CONNECT = 'CONNECT', 'Establish a connection to the server.' + DELETE = 'DELETE', 'Remove the target.' + GET = 'GET', 'Retrieve the target.' + HEAD = 'HEAD', 'Same as GET, but only retrieve the status line and header section.' + OPTIONS = 'OPTIONS', 'Describe the communication options for the target.' + PATCH = 'PATCH', 'Apply partial modifications to a target.' + POST = 'POST', 'Perform target-specific processing with the request payload.' + PUT = 'PUT', 'Replace the target with the request payload.' + TRACE = 'TRACE', 'Perform a message loop-back test along the path to the target.' From 38204c0a7bdfedc667502ced9aae70ccdb63fd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 21 Jun 2023 13:41:28 -0300 Subject: [PATCH 15/35] Add some typing to the `keys` function. --- .../opentelemetry/instrumentation/aiohttp_server/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index aa2a87b047..470a1b7b80 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -2,6 +2,7 @@ from aiohttp import web from multidict import CIMultiDictProxy from timeit import default_timer +from typing import Tuple, Dict, List from opentelemetry import context, trace, metrics from opentelemetry.instrumentation.aiohttp_server.package import _instruments @@ -15,8 +16,6 @@ from opentelemetry.util.http import get_excluded_urls from opentelemetry.util.http import remove_url_credentials -from typing import Tuple - _SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation" @@ -165,7 +164,7 @@ def get(self, carrier, key: str): return None return headers.getall(key, None) - def keys(self, carrier: dict): + def keys(self, carrier: Dict) -> List: return list(carrier.keys()) From e235e7e728bcd1407268765eccefe9d368802c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 21 Jun 2023 13:56:42 -0300 Subject: [PATCH 16/35] Add Python 3.11 as a supported version by the library. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e47f27a770..619a72a312 100644 --- a/tox.ini +++ b/tox.ini @@ -30,7 +30,7 @@ envlist = pypy3-test-instrumentation-aiohttp-client ; opentelemetry-instrumentation-aiohttp-server - py3{6,7,8,9,10}-test-instrumentation-aiohttp-server + py3{6,7,8,9,10,11}-test-instrumentation-aiohttp-server pypy3-test-instrumentation-aiohttp-server ; opentelemetry-instrumentation-aiopg From 9a551b188f0c7f403551495a25e85fb2afc94470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 21 Jun 2023 13:58:12 -0300 Subject: [PATCH 17/35] Fixes some typos and add more typing to the code. --- .../instrumentation/aiohttp_server/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 470a1b7b80..702aa16520 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -2,7 +2,7 @@ from aiohttp import web from multidict import CIMultiDictProxy from timeit import default_timer -from typing import Tuple, Dict, List +from typing import Tuple, Dict, List, Union from opentelemetry import context, trace, metrics from opentelemetry.instrumentation.aiohttp_server.package import _instruments @@ -148,16 +148,16 @@ def set_status_code(span, status_code): class AiohttpGetter(Getter): """Extract current trace from headers""" - def get(self, carrier, key: str): - """Getter implementation to retrieve a HTTP header value from the ASGI + def get(self, carrier, key: str) -> Union[List, None]: + """Getter implementation to retrieve an HTTP header value from the ASGI scope. Args: carrier: ASGI scope object key: header name in scope Returns: - A list with a single string with the header value if it exists, - else None. + A list of all header values matching the key, or None if the key + does not match any header. """ headers: CIMultiDictProxy = carrier.headers if not headers: From 82d3b8dcfcd1843586494e8d73a1f66bfb7c0c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 21 Jun 2023 14:32:17 -0300 Subject: [PATCH 18/35] Add better docstrings and also some types. --- .../instrumentation/aiohttp_server/__init__.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 702aa16520..20c2f5b541 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -63,7 +63,7 @@ def _parse_active_request_count_attrs(req_attrs): def get_default_span_details(request: web.Request) -> Tuple[str, dict]: """Default implementation for get_default_span_details Args: - scope: the asgi scope dictionary + request: the request object itself. Returns: a tuple of the span name, and any attributes to attach to the span. """ @@ -71,15 +71,20 @@ def get_default_span_details(request: web.Request) -> Tuple[str, dict]: return span_name, {} -def _get_view_func(request) -> str: - """TODO: is this useful??""" +def _get_view_func(request: web.Request) -> str: + """Returns the name of the request handler. + Args: + request: the request object itself. + Returns: + a string containing the name of the handler function + """ try: return request.match_info.handler.__name__ except AttributeError: return "unknown" -def collect_request_attributes(request: web.Request): +def collect_request_attributes(request: web.Request) -> Dict: """Collects HTTP request attributes from the ASGI scope and returns a dictionary to be used as span creation attributes.""" @@ -125,10 +130,9 @@ def collect_request_attributes(request: web.Request): return result -def set_status_code(span, status_code): +def set_status_code(span, status_code: int) -> None: """Adds HTTP response attributes to span using the status_code argument.""" - if not span.is_recording(): - return + try: status_code = int(status_code) except ValueError: From 74fece8cfbf762d57eadefbbcd4a9660745700f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 23 Jun 2023 14:09:23 -0300 Subject: [PATCH 19/35] Inject context into span to avoid it being orphaned. Co-authored-by: Kenny Trytek --- .../src/opentelemetry/instrumentation/aiohttp_server/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 20c2f5b541..8cb4f10e1f 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -205,6 +205,7 @@ async def middleware(request, handler): with tracer.start_as_current_span( span_name, + context=extract(request, getter=getter), kind=trace.SpanKind.SERVER, ) as span: attributes = collect_request_attributes(request) From 836a738305be601dfc7efd1de2eae77bb31be294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Mon, 21 Aug 2023 14:52:18 -0300 Subject: [PATCH 20/35] Bump dependencies and lib versions. --- .../pyproject.toml | 6 +++--- .../opentelemetry/instrumentation/aiohttp_server/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 8596a9c425..b615b86c20 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -26,9 +26,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.39b0.dev", - "opentelemetry-semantic-conventions == 0.39b0.dev", - "opentelemetry-util-http == 0.39b0.dev", + "opentelemetry-instrumentation == 0.40b0.dev", + "opentelemetry-semantic-conventions == 0.40b0.dev", + "opentelemetry-util-http == 0.40b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index eb62a67e28..87b20fddc3 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.39b0.dev" +__version__ = "0.40b0.dev" From 40c6e3da65a7e0b84c13c9bf5205683a4fb5ee60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Mon, 21 Aug 2023 14:52:46 -0300 Subject: [PATCH 21/35] Correctly import `extract`. --- .../src/opentelemetry/instrumentation/aiohttp_server/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 8cb4f10e1f..164920a500 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -10,6 +10,7 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import http_status_to_status_code from opentelemetry.propagators.textmap import Getter +from opentelemetry.propagate import extract from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.semconv.metrics import MetricInstruments from opentelemetry.trace.status import Status, StatusCode From cd569b14a0de579306dfdd767717e7334ed237d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 31 Aug 2023 17:29:52 -0300 Subject: [PATCH 22/35] Revert the bootstrap.py file changes --- .../src/opentelemetry/instrumentation/bootstrap.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py index bb0044850a..6fa36f0463 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py @@ -103,11 +103,13 @@ def _is_installed(req): def _find_installed_libraries(): libs = default_instrumentations[:] - - for _, v in libraries.items(): - if _is_installed(v["library"]): - libs.extend(v["instrumentation"]) - + libs.extend( + [ + v["instrumentation"] + for _, v in libraries.items() + if _is_installed(v["library"]) + ] + ) return libs From 98c0f4216224811f2257e6b9fb0fe76c660e23a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 31 Aug 2023 17:31:16 -0300 Subject: [PATCH 23/35] Remove the of iter_entry_points from pkg_resources. --- .../tests/test_aiohttp_server_integration.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 115759def7..48cf1240e5 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -17,13 +17,13 @@ import aiohttp from http import HTTPStatus from .utils import HTTPMethod -from pkg_resources import iter_entry_points from unittest import mock from opentelemetry import trace as trace_api from opentelemetry.test.test_base import TestBase from opentelemetry.instrumentation.aiohttp_server import AioHttpServerInstrumentor from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.util._importlib_metadata import entry_points from opentelemetry.test.globals_test import ( reset_trace_globals, @@ -67,11 +67,10 @@ async def server_fixture(tracer, aiohttp_server): def test_checking_instrumentor_pkg_installed(): - entry_points = iter_entry_points( - "opentelemetry_instrumentor", "aiohttp-server" - ) + itered_entry_points = iter(entry_points( + "opentelemetry_instrumentor", "aiohttp-server")) - instrumentor = next(entry_points).load()() + instrumentor = next(itered_entry_points).load()() assert (isinstance(instrumentor, AioHttpServerInstrumentor)) From 3c1a0b26468e454a1098373c39e05d6daa429c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 31 Aug 2023 17:32:32 -0300 Subject: [PATCH 24/35] Sync the package version with the one on pyproject.toml. --- .../src/opentelemetry/instrumentation/aiohttp_server/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py index bd7c16572a..557f1a54a9 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/package.py @@ -13,4 +13,4 @@ # limitations under the License. -_instruments = ("aiohttp ~= 3.8",) +_instruments = ("aiohttp ~= 3.0",) From a76f1df98b8cc0665c5d2426b2899416b54c942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Mon, 4 Sep 2023 20:47:11 -0300 Subject: [PATCH 25/35] Fixes the library version and bumps OpenTelemetry dependency versions. --- .../pyproject.toml | 6 +++--- .../opentelemetry/instrumentation/aiohttp_server/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index b615b86c20..392f849021 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -26,9 +26,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.40b0.dev", - "opentelemetry-semantic-conventions == 0.40b0.dev", - "opentelemetry-util-http == 0.40b0.dev", + "opentelemetry-instrumentation == 0.41b0.dev", + "opentelemetry-semantic-conventions == 0.41b0.dev", + "opentelemetry-util-http == 0.41b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index 87b20fddc3..7f88144cf6 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.40b0.dev" +__version__ = "0.41b0.dev" From 7b4e50c70a41f4b75ecc51f5ca3c88e54d573d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Wed, 6 Sep 2023 09:27:57 -0300 Subject: [PATCH 26/35] Bump opentelemetry dependencies and this lib itself to 0.42b0. --- .../pyproject.toml | 6 +++--- .../opentelemetry/instrumentation/aiohttp_server/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml index 392f849021..77bfa08b11 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/pyproject.toml @@ -26,9 +26,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.12", - "opentelemetry-instrumentation == 0.41b0.dev", - "opentelemetry-semantic-conventions == 0.41b0.dev", - "opentelemetry-util-http == 0.41b0.dev", + "opentelemetry-instrumentation == 0.42b0.dev", + "opentelemetry-semantic-conventions == 0.42b0.dev", + "opentelemetry-util-http == 0.42b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py index 7f88144cf6..c2996671d6 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.41b0.dev" +__version__ = "0.42b0.dev" From bde869ca3ee732ae8fdf43b327bc0182644cc166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 8 Sep 2023 09:48:24 -0300 Subject: [PATCH 27/35] Remove the usage of `round` to allow a more precise value. --- .../opentelemetry/instrumentation/aiohttp_server/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index 164920a500..eed5090cc2 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -221,7 +221,7 @@ async def middleware(request, handler): set_status_code(span, ex.status_code) raise finally: - duration = max(round((default_timer() - start) * 1000), 0) + duration = max((default_timer() - start) * 1000, 0) duration_histogram.record(duration, duration_attrs) active_requests_counter.add(-1, active_requests_count_attrs) return resp From 4397a46eda0d44532e27bdc683618e70fe13f70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Fri, 8 Sep 2023 09:55:03 -0300 Subject: [PATCH 28/35] Add a CHANGELOG entry. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1206844e55..ec42e3b3f4 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 +- `opentelemetry-instrumentation-aiohttp-server` Add instrumentor and auto instrumentation support for aiohttp-server + ([#1800](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1800)) + ## Version 1.20.0/0.41b0 (2023-09-01) ### Fixed From 75f2aad525caf0799894e106a1f813b455450c02 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 29 Sep 2023 17:42:19 +0200 Subject: [PATCH 29/35] Adding updates from tox -e generate --- instrumentation/README.md | 1 + .../src/opentelemetry/instrumentation/bootstrap_gen.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/instrumentation/README.md b/instrumentation/README.md index 12b8ada105..cc5ea02def 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -3,6 +3,7 @@ | --------------- | ------------------ | --------------- | | [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-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 6815d56644..c7acc063c1 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -22,10 +22,11 @@ }, "aiohttp": { "library": "aiohttp ~= 3.0", - "instrumentation": [ - "opentelemetry-instrumentation-aiohttp-client==0.42b0.dev", - "opentelemetry-instrumentation-aiohttp-server==0.42b0.dev", - ], + "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.42b0.dev", + }, + "aiohttp": { + "library": "aiohttp ~= 3.0", + "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.42b0.dev", }, "aiopg": { "library": "aiopg >= 0.13.0, < 2.0.0", From 26393c6df3b91fe79c80bdb8459ba3f43e62d6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 12 Oct 2023 14:26:54 -0300 Subject: [PATCH 30/35] Remove a skiped test. --- .../tests/test_aiohttp_server_integration.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 48cf1240e5..3438bb7afb 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -17,7 +17,6 @@ import aiohttp from http import HTTPStatus from .utils import HTTPMethod -from unittest import mock from opentelemetry import trace as trace_api from opentelemetry.test.test_base import TestBase @@ -101,23 +100,3 @@ async def test_status_code_instrumentation(tracer, server_fixture, assert f"http://{server.host}:{server.port}{url}" == span.attributes[ SpanAttributes.HTTP_URL ] - - -@pytest.mark.skip(reason="Historical purposes. Can't see the reason of this mock.") -def test_not_recording(self): - 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 patched: - patched.start_span.return_value = mock_span - # pylint: disable=W0612 - # host, port = run_with_test_server( - # self.get_default_request(), self.URL, self.default_handler - # ) - - self.assertTrue(patched.start_span.called) - self.assertFalse(mock_span.is_recording()) - self.assertTrue(mock_span.is_recording.called) - self.assertFalse(mock_span.set_attribute.called) - self.assertFalse(mock_span.set_status.called) From 96300f5a635111ce8a945c2f98bfdc3f0c3b8432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 12 Oct 2023 15:33:06 -0300 Subject: [PATCH 31/35] Add LICENSE header. --- .../tests/utils.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py index bbe1ce49bd..287f7b695e 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py @@ -1,15 +1,22 @@ -# This was adapted from Python 3.11 http module. +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from enum import Enum class HTTPMethod(Enum): - """HTTP methods and descriptions - - Methods from the following RFCs are all observed: - - * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - * RFC 5789: PATCH Method for HTTP - """ + """HTTP methods and descriptions""" def __repr__(self): return self.value[0] From 9809d79caa473556e7d3da5c2574e11818640012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 12 Oct 2023 15:33:37 -0300 Subject: [PATCH 32/35] Add LICENSE header and fixes the use of a constant. --- .../instrumentation/aiohttp_server/__init__.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index eed5090cc2..3fd8e62e78 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -1,3 +1,17 @@ +# Copyright 2020, OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import urllib from aiohttp import web from multidict import CIMultiDictProxy @@ -5,6 +19,7 @@ from typing import Tuple, Dict, List, Union from opentelemetry import context, trace, metrics +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.aiohttp_server.package import _instruments from opentelemetry.instrumentation.aiohttp_server.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -17,9 +32,6 @@ from opentelemetry.util.http import get_excluded_urls from opentelemetry.util.http import remove_url_credentials - -_SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation" - _duration_attrs = [ SpanAttributes.HTTP_METHOD, SpanAttributes.HTTP_HOST, From fbbe270fabffd67399a6560812d58072cdce7582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Thu, 12 Oct 2023 15:34:00 -0300 Subject: [PATCH 33/35] Fix linter issues. --- .../tests/test_aiohttp_server_integration.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 3438bb7afb..f5d1b31984 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -78,10 +78,14 @@ def test_checking_instrumentor_pkg_installed(): ("/test-path", HTTPMethod.GET, HTTPStatus.OK), ("/not-found", HTTPMethod.GET, HTTPStatus.NOT_FOUND) ]) -async def test_status_code_instrumentation(tracer, server_fixture, - aiohttp_client, url, - expected_method, - expected_status_code): +async def test_status_code_instrumentation( + tracer, + server_fixture, + aiohttp_client, + url, + expected_method, + expected_status_code +): _, memory_exporter = tracer server, app = server_fixture From 782e4e8d0ddb14e6f1b395a726f4dcbd72d10e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Mon, 16 Oct 2023 19:06:43 -0300 Subject: [PATCH 34/35] Change the HTTPMethod Enum. --- .../tests/utils.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py index 287f7b695e..8fedcb32e3 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/utils.py @@ -19,14 +19,14 @@ class HTTPMethod(Enum): """HTTP methods and descriptions""" def __repr__(self): - return self.value[0] + return f"{self.value}" - CONNECT = 'CONNECT', 'Establish a connection to the server.' - DELETE = 'DELETE', 'Remove the target.' - GET = 'GET', 'Retrieve the target.' - HEAD = 'HEAD', 'Same as GET, but only retrieve the status line and header section.' - OPTIONS = 'OPTIONS', 'Describe the communication options for the target.' - PATCH = 'PATCH', 'Apply partial modifications to a target.' - POST = 'POST', 'Perform target-specific processing with the request payload.' - PUT = 'PUT', 'Replace the target with the request payload.' - TRACE = 'TRACE', 'Perform a message loop-back test along the path to the target.' + CONNECT = 'CONNECT' + DELETE = 'DELETE' + GET = 'GET' + HEAD = 'HEAD' + OPTIONS = 'OPTIONS' + PATCH = 'PATCH' + POST = 'POST' + PUT = 'PUT' + TRACE = 'TRACE' From c22e3000c2cf62b55b73a701f6de3b360d023cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=22decko=22=20de=20Brito?= Date: Mon, 16 Oct 2023 19:07:00 -0300 Subject: [PATCH 35/35] Fixes some tests. --- .../tests/test_aiohttp_server_integration.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index f5d1b31984..973aea0d1c 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -66,10 +66,9 @@ async def server_fixture(tracer, aiohttp_server): def test_checking_instrumentor_pkg_installed(): - itered_entry_points = iter(entry_points( - "opentelemetry_instrumentor", "aiohttp-server")) - instrumentor = next(itered_entry_points).load()() + (instrumentor_entrypoint,) = entry_points(group="opentelemetry_instrumentor", name="aiohttp-server") + instrumentor = instrumentor_entrypoint.load()() assert (isinstance(instrumentor, AioHttpServerInstrumentor)) @@ -98,7 +97,7 @@ async def test_status_code_instrumentation( [span] = memory_exporter.get_finished_spans() - assert expected_method == span.attributes[SpanAttributes.HTTP_METHOD] + assert expected_method.value == span.attributes[SpanAttributes.HTTP_METHOD] assert expected_status_code == span.attributes[SpanAttributes.HTTP_STATUS_CODE] assert f"http://{server.host}:{server.port}{url}" == span.attributes[