From fc3bcff1db9b74eb3744f888e7437b07169d1797 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 13:23:37 +0900 Subject: [PATCH 01/50] add asyncio instrumentation --- CONTRIBUTING.md | 2 +- .../LICENSE | 201 ++++++++++++++++ .../README.rst | 24 ++ .../pyproject.toml | 54 +++++ .../instrumentation/asyncio/__init__.py | 221 ++++++++++++++++++ .../instrumentation/asyncio/package.py | 15 ++ .../instrumentation/asyncio/version.py | 15 ++ .../tests/__init__.py | 13 ++ .../tests/common_test_func.py | 50 ++++ .../tests/test_asyncio_cancellation.py | 38 +++ .../tests/test_asyncio_create_task.py | 40 ++++ .../tests/test_asyncio_ensure_future.py | 57 +++++ .../tests/test_asyncio_gather.py | 48 ++++ .../tests/test_asyncio_integration.py | 44 ++++ .../test_asyncio_run_coroutine_threadsafe.py | 54 +++++ .../tests/test_asyncio_taskgroup.py | 59 +++++ .../tests/test_asyncio_to_thread.py | 45 ++++ .../tests/test_asyncio_wait.py | 74 ++++++ 18 files changed, 1053 insertions(+), 1 deletion(-) create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/LICENSE create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/README.rst create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/package.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41f2aa08cb..90d3452f07 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -198,7 +198,7 @@ The continuation integration overrides that environment variable with as per the Below is a checklist of things to be mindful of when implementing a new instrumentation or working on a specific instrumentation. It is one of our goals as a community to keep the implementation specific details of instrumentations as similar across the board as possible for ease of testing and feature parity. It is also good to abstract as much common functionality as possible. - Follow semantic conventions - - The instrumentation should follow the semantic conventions defined [here](https://github.com/open-telemetry/opentelemetry-specification/tree/main/semantic_conventions) + - The instrumentation should follow the semantic conventions defined [here](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/semantic-conventions.md) - Extends from [BaseInstrumentor](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py#L26) - Supports auto-instrumentation - Add an entry point (ex. https://github.com/open-telemetry/opentelemetry-python-contrib/blob/f045c43affff6ff1af8fa2f7514a4fdaca97dacf/instrumentation/opentelemetry-instrumentation-requests/pyproject.toml#L44) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright The OpenTelemetry Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst new file mode 100644 index 0000000000..c709513877 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -0,0 +1,24 @@ +OpenTelemetry asyncio Instrumentation +=========================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-asyncio.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-asyncio/ + +This library allows tracing requests made by the asyncio library. + +Installation +------------ + +:: + + pip install opentelemetry-instrumentation-asyncio + + +References +---------- + +* `OpenTelemetry asyncio/ Tracing /.html>`_ +* `OpenTelemetry Project `_ +* `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml new file mode 100644 index 0000000000..0a4fb673c2 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -0,0 +1,54 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-instrumentation-asyncio" +dynamic = ["version"] +description = "OpenTelemetry instrumentation for asyncio" +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.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", + "wrapt >= 1.0.0, < 2.0.0", +] + +[project.optional-dependencies] +test = [ + "opentelemetry-instrumentation-asyncio[instruments]", + "opentelemetry-test-utils == 0.41b0.dev", +] + +[project.entry-points.opentelemetry_instrumentor] +asyncio = "opentelemetry.instrumentation.asyncio:AsyncioInstrumentor" + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-asyncio" + +[tool.hatch.version] +path = "src/opentelemetry/instrumentation/asyncio/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py new file mode 100644 index 0000000000..3ae18a4cc2 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -0,0 +1,221 @@ +# 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. +""" +.. asyncio: https://github.com/python/asyncio + +Usage +----- + +.. code-block:: python + + import asyncio + from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + AsyncioInstrumentor().instrument() + + async def main(): + await asyncio.create_task(asyncio.sleep(0.1)) + + asyncio.run(main()) + +API +--- +""" +import asyncio +import sys +from asyncio import futures +from typing import Collection + +from opentelemetry.trace import get_tracer +from opentelemetry.trace.status import Status, StatusCode +from wrapt import wrap_function_wrapper as _wrap + +from opentelemetry.instrumentation.asyncio.package import _instruments +from opentelemetry.instrumentation.asyncio.version import __version__ +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap + +ASYNCIO_PREFIX = "asyncio." + + +class AsyncioInstrumentor(BaseInstrumentor): + """ + An instrumentor for asyncio + + See `BaseInstrumentor` + """ + + methods_with_coroutine = [ + "create_task", + "ensure_future", + "wait_for", + "wait", + "as_completed", + "run_coroutine_threadsafe", + ] + + def __init__(self): + super().__init__() + self._tracer = None + + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + + def _instrument(self, **kwargs): + tracer_provider = kwargs.get("tracer_provider") + self._tracer = get_tracer( + __name__, __version__, tracer_provider + ) + for method in self.methods_with_coroutine: + self.instrument_method_with_coroutine(method) + + self.instrument_gather() + self.instrument_to_thread() + self.instrument_taskgroup_create_task() + + def _uninstrument(self, **kwargs): + for method in self.methods_with_coroutine: + self.uninstrument_method_with_coroutine(method) + self.uninstrument_gather() + self.uninstrument_to_thread() + self.uninstrument_taskgroup_create_task() + + def instrument_method_with_coroutine(self, method_name): + """ + Instruments specified asyncio method. + """ + + def wrap_coro_or_future(method, instance, args, kwargs): + + # If the first argument is a coroutine or future, + # we decorate it with a span and return the task. + if args and len(args) > 0: + first_arg = args[0] + # Check if it's a coroutine or future and wrap it + if asyncio.iscoroutine(first_arg) or futures.isfuture(first_arg): + args = (self.trace_item(first_arg),) + args[1:] + # Check if it's a list and wrap each item + elif isinstance(first_arg, list): + args = ([self.trace_item(item) for item in first_arg],) + args[1:] + return method(*args, **kwargs) + + _wrap(asyncio, method_name, wrap_coro_or_future) + + def uninstrument_method_with_coroutine(self, method_name): + """ + Uninstrument specified asyncio method. + """ + unwrap(asyncio, method_name) + + def instrument_gather(self): + + def wrap_coros_or_futures(method, instance, args, kwargs): + if args and len(args) > 0: + # Check if it's a coroutine or future and wrap it + wrapped_args = tuple(self.trace_item(item) for item in args) + return method(*wrapped_args, **kwargs) + + _wrap(asyncio, "gather", wrap_coros_or_futures) + + def uninstrument_gather(self): + unwrap(asyncio, "gather") + + def instrument_to_thread(self): + def wrap_to_thread(method, instance, args, kwargs): + if args: + first_arg = args[0] + # Wrap the first argument + wrapped_first_arg = self.trace_func(first_arg) + wrapped_args = (wrapped_first_arg,) + args[1:] + + return method(*wrapped_args, **kwargs) + + _wrap(asyncio, "to_thread", wrap_to_thread) + + def uninstrument_to_thread(self): + unwrap(asyncio, "to_thread") + + def instrument_taskgroup_create_task(self): + if sys.version_info >= (3, 11): + def wrap_taskgroup_create_task(method, instance, args, kwargs): + if args: + coro = args[0] + wrapped_coro = self.trace_coroutine(coro) + wrapped_args = (wrapped_coro,) + args[1:] + return method(*wrapped_args, **kwargs) + + _wrap(asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task) + + def uninstrument_taskgroup_create_task(self): + if sys.version_info >= (3, 11): + unwrap(asyncio.TaskGroup, "create_task") + + def trace_func(self, func): + """Trace a function.""" + with self._tracer.start_as_current_span(f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__) as span: + try: + return func + except Exception as exc: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exc) + raise + + def trace_item(self, coro_or_future): + """Trace a coroutine or future item.""" + # Task is already traced, return it + if isinstance(coro_or_future, asyncio.Task): + return coro_or_future + if asyncio.iscoroutine(coro_or_future): + return self.trace_coroutine(coro_or_future) + elif futures.isfuture(coro_or_future): + return self.trace_future(coro_or_future) + return coro_or_future + + async def trace_coroutine(self, coro): + + with self._tracer.start_as_current_span(f"{ASYNCIO_PREFIX}coro-" + coro.__name__) as span: + exception = None # Initialize the exception variable + try: + return await coro + # CancelledError is raised when a coroutine is cancelled + # before it has a chance to run. We don't want to record + # this as an error. + except asyncio.CancelledError: + pass + except (asyncio.TimeoutError, + asyncio.InvalidStateError, + asyncio.SendfileNotAvailableError, + asyncio.IncompleteReadError, + asyncio.LimitOverrunError, + asyncio.BrokenBarrierError, + Exception) as exc: # General exception should be the last + exception = exc + raise + finally: + if span.is_recording() and exception: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exception) + + def trace_future(self, future): + span = self._tracer.start_span(f"{ASYNCIO_PREFIX}" + future.__class__.__name__) + + def callback(f): + exception = f.exception() + if exception: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exception) + span.end() + + future.add_done_callback(callback) + return future diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/package.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/package.py new file mode 100644 index 0000000000..484f6e9c58 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/package.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. + +_instruments = tuple() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py new file mode 100644 index 0000000000..c2996671d6 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/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.42b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py new file mode 100644 index 0000000000..eacf7c9c0e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py new file mode 100644 index 0000000000..570136f52f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py @@ -0,0 +1,50 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio + + +async def async_func(): + await asyncio.sleep(1) + + +async def factorial(name, number): + f = 1 + for i in range(2, number + 1): + print(f"Task {name}: Compute factorial({number}), currently i={i}...") + await asyncio.sleep(0) + f *= i + print(f"Task {name}: factorial({number}) = {f}") + return f + + +async def cancellable_coroutine(): + await asyncio.sleep(2) + + +async def cancellation_coro(): + task = asyncio.create_task(cancellable_coroutine()) + + await asyncio.sleep(0.1) + task.cancel() + + await task + + +async def cancellation_create_task(): + await asyncio.create_task(cancellation_coro()) + + +async def ensure_future(): + await asyncio.ensure_future(asyncio.sleep(0)) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py new file mode 100644 index 0000000000..c8419ecc02 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -0,0 +1,38 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from .common_test_func import cancellation_create_task +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioCancel(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_cancel(self): + asyncio.run(cancellation_create_task()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 2) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py new file mode 100644 index 0000000000..5d1edb40a2 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -0,0 +1,40 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioCreateTask(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_asyncio_create_task(self): + async def async_func(): + await asyncio.create_task(asyncio.sleep(0)) + + asyncio.run(async_func()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py new file mode 100644 index 0000000000..42ed1a1c29 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -0,0 +1,57 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +import pytest +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from .common_test_func import async_func + + +class TestAsyncioEnsureFuture(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + @pytest.mark.asyncio + def test_asyncio_loop_ensure_future(self): + loop = asyncio.get_event_loop() + task = asyncio.ensure_future(async_func()) + loop.run_until_complete(task) + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + self.assertEqual(spans[0].name, "asyncio.coro-async_func") + + @pytest.mark.asyncio + def test_asyncio_ensure_future_with_future(self): + loop = asyncio.get_event_loop() + + future = asyncio.Future() + future.set_result(1) + task = asyncio.ensure_future(future) + loop.run_until_complete(task) + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + self.assertEqual(spans[0].name, "asyncio.Future") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py new file mode 100644 index 0000000000..ea02612893 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -0,0 +1,48 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from .common_test_func import factorial +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioGather(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_asyncio_gather(self): + async def gather_factorial(): + await asyncio.gather( + factorial("A", 2), + factorial("B", 3), + factorial("C", 4) + ) + + asyncio.run(gather_factorial()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 3) + self.assertEqual(spans[0].name, "asyncio.coro-factorial") + self.assertEqual(spans[1].name, "asyncio.coro-factorial") + self.assertEqual(spans[2].name, "asyncio.coro-factorial") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py new file mode 100644 index 0000000000..b10a327bc6 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py @@ -0,0 +1,44 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from .common_test_func import ensure_future +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioInstrumentor(TestBase): + def setUp(self): + super().setUp() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + + def test_asyncio_integration(self): + AsyncioInstrumentor().instrument() + + asyncio.run(ensure_future()) + spans = self.memory_exporter.get_finished_spans() + self.memory_exporter.clear() + assert spans + AsyncioInstrumentor().uninstrument() + + asyncio.run(ensure_future()) + spans = self.memory_exporter.get_finished_spans() + assert not spans diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py new file mode 100644 index 0000000000..000168509f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py @@ -0,0 +1,54 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import threading +from concurrent.futures import ThreadPoolExecutor + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestRunCoroutineThreadSafe(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self.loop = asyncio.new_event_loop() + self.executor = ThreadPoolExecutor(max_workers=1) + self.loop.set_default_executor(self.executor) + self.thread = threading.Thread(target=self.loop.run_forever) + self.thread.start() + + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + self.loop.call_soon_threadsafe(self.loop.stop) + self.thread.join() + self.loop.close() + + AsyncioInstrumentor().uninstrument() + + def test_run_coroutine_threadsafe(self): + async def coro(): + return 42 + + future = asyncio.run_coroutine_threadsafe(coro(), self.loop) + result = future.result(timeout=1) + self.assertEqual(result, 42) + spans = self.memory_exporter.get_finished_spans() + assert spans diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py new file mode 100644 index 0000000000..6063972068 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -0,0 +1,59 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import sys + +import aiotools +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from .common_test_func import async_func +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + +py11 = False +if sys.version_info >= (3, 11): + py11 = True + + +class TestAsyncioTaskgroup(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_task_group_create_task(self): + async def main(): + if py11: + async with asyncio.TaskGroup() as tg: + for _ in range(10): + tg.create_task(async_func()) + else: + async with aiotools.TaskGroup() as tg: + for _ in range(10): + tg.create_task(async_func()) + + asyncio.run(main()) + spans = self.memory_exporter.get_finished_spans() + assert spans + if py11: + self.assertEqual(len(spans), 10) + else: + # aiotools.TaskGroup is Out of scope of support. + self.assertEqual(len(spans), 0) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py new file mode 100644 index 0000000000..04afb945ff --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -0,0 +1,45 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioToThread(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_to_thread(self): + def multiply(x, y): + return x * y + + async def to_thread(): + result = await asyncio.to_thread(multiply, 2, 3) + assert result == 6 + + asyncio.run(to_thread()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + assert spans[0].name == "asyncio.to_thread_func-multiply" diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py new file mode 100644 index 0000000000..070617ca94 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py @@ -0,0 +1,74 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import sys + +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import get_tracer + +from .common_test_func import async_func +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + +class TestAsyncioWait(TestBase): + def setUp(self): + super().setUp() + AsyncioInstrumentor().instrument() + self._tracer = get_tracer( + __name__, + ) + + def tearDown(self): + super().tearDown() + AsyncioInstrumentor().uninstrument() + + def test_asyncio_wait_with_create_task(self): + + async def main(): + if sys.version_info >= (3, 11): + # In Python 3.11, you can't send coroutines directly to asyncio.wait(). + # Instead, you must wrap them in asyncio.create_task(). + tasks = [asyncio.create_task(async_func()), asyncio.create_task(async_func())] + await asyncio.wait(tasks) + else: + await asyncio.wait([async_func(), async_func()]) + + asyncio.run(main()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 2) + + def test_asyncio_wait_for(self): + async def main(): + await asyncio.wait_for(async_func(), 1) + await asyncio.wait_for(async_func(), 1) + + asyncio.run(main()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 2) + + def test_asyncio_as_completed(self): + async def main(): + if sys.version_info >= (3, 11): + # In Python 3.11, you can't send coroutines directly to asyncio.as_completed(). + # Instead, you must wrap them in asyncio.create_task(). + tasks = [asyncio.create_task(async_func()), asyncio.create_task(async_func())] + for task in asyncio.as_completed(tasks): + await task + else: + for task in asyncio.as_completed([async_func(), async_func()]): + await task + + asyncio.run(main()) + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 2) From e05b02b67ec23ef442aefbe3ceca893be430b30a Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 14:06:54 +0900 Subject: [PATCH 02/50] add asyncio instrumentation --- tox.ini | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tox.ini b/tox.ini index b4fe0690a8..6ab38ba3e6 100644 --- a/tox.ini +++ b/tox.ini @@ -232,6 +232,10 @@ envlist = ; // FIXME: Enable support for python 3.11 when https://github.com/confluentinc/confluent-kafka-python/issues/1452 is fixed py3{7,8,9,10}-test-instrumentation-confluent-kafka + ; opentelemetry-instrumentation-asyncio + py3{7,8,9,10,11}-test-instrumentation-asyncio + + lint spellcheck docker-tests @@ -343,6 +347,7 @@ changedir = test-instrumentation-tortoiseorm: instrumentation/opentelemetry-instrumentation-tortoiseorm/tests test-instrumentation-wsgi: instrumentation/opentelemetry-instrumentation-wsgi/tests test-instrumentation-httpx{18,21}: instrumentation/opentelemetry-instrumentation-httpx/tests + test-instrumentation-asyncio: instrumentation/opentelemetry-instrumentation-asyncio/tests test-util-http: util/opentelemetry-util-http/tests test-sdkextension-aws: sdk-extension/opentelemetry-sdk-extension-aws/tests test-resource-detector-container: resource/opentelemetry-resource-detector-container/tests @@ -455,6 +460,8 @@ commands_pre = elasticsearch{2,5,6}: pip install {toxinidir}/opentelemetry-instrumentation[test] {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] + asyncio: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] + httpx{18,21}: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] sdkextension-aws: pip install {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] @@ -564,6 +571,7 @@ commands_pre = python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write[test] python -m pip install -e {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] From 143000ae314ce7dc51cbae6a227d9bc6edd0ddc5 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 14:32:24 +0900 Subject: [PATCH 03/50] modify test configure --- .../pyproject.toml | 6 ++++++ .../tests/test_asyncio_taskgroup.py | 10 +--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 0a4fb673c2..45c27e3bdb 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -29,6 +29,12 @@ dependencies = [ "wrapt >= 1.0.0, < 2.0.0", ] +[project.optional-dependencies] +instruments = [] +test = [ + "opentelemetry-test-utils == 0.41b0.dev", +] + [project.optional-dependencies] test = [ "opentelemetry-instrumentation-asyncio[instruments]", diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py index 6063972068..33a2456f86 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -14,12 +14,11 @@ import asyncio import sys -import aiotools from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from .common_test_func import async_func from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from .common_test_func import async_func py11 = False if sys.version_info >= (3, 11): @@ -44,16 +43,9 @@ async def main(): async with asyncio.TaskGroup() as tg: for _ in range(10): tg.create_task(async_func()) - else: - async with aiotools.TaskGroup() as tg: - for _ in range(10): - tg.create_task(async_func()) asyncio.run(main()) spans = self.memory_exporter.get_finished_spans() assert spans if py11: self.assertEqual(len(spans), 10) - else: - # aiotools.TaskGroup is Out of scope of support. - self.assertEqual(len(spans), 0) From 5eb088d29ddd46ab6709161256a73a1edfe21581 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 14:44:58 +0900 Subject: [PATCH 04/50] modify test configure --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 7 ++----- .../src/opentelemetry/instrumentation/asyncio/version.py | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 45c27e3bdb..11d60bcb01 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -31,14 +31,11 @@ dependencies = [ [project.optional-dependencies] instruments = [] -test = [ - "opentelemetry-test-utils == 0.41b0.dev", -] - -[project.optional-dependencies] test = [ "opentelemetry-instrumentation-asyncio[instruments]", "opentelemetry-test-utils == 0.41b0.dev", + "pytest", + "wrapt >= 1.0.0, < 2.0.0", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py index c2996671d6..7f88144cf6 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.42b0.dev" +__version__ = "0.41b0.dev" From 0b3da0ee3244d5f0905ac10b4a1d51b7c74639ef Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 14:55:25 +0900 Subject: [PATCH 05/50] modify tox generate result --- instrumentation/README.md | 1 + .../opentelemetry-instrumentation-asyncio/pyproject.toml | 2 +- opentelemetry-contrib-instrumentations/pyproject.toml | 1 + .../src/opentelemetry/instrumentation/bootstrap_gen.py | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/instrumentation/README.md b/instrumentation/README.md index 4a4e3cc6da..c6ba2ebf9b 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -5,6 +5,7 @@ | [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No | [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No | [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | No +| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No | [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No | [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No | [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 11d60bcb01..8341405ca7 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -47,7 +47,7 @@ Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/ [tool.hatch.version] path = "src/opentelemetry/instrumentation/asyncio/version.py" -[tool.hatch.build.targets.sdist] +[tool.hatch.build.targets.sdist include = [ "/src", "/tests", diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index f43c3075bc..e2b5edf48d 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -33,6 +33,7 @@ dependencies = [ "opentelemetry-instrumentation-aiohttp-client==0.41b0.dev", "opentelemetry-instrumentation-aiopg==0.41b0.dev", "opentelemetry-instrumentation-asgi==0.41b0.dev", + "opentelemetry-instrumentation-asyncio==0.41b0.dev", "opentelemetry-instrumentation-asyncpg==0.41b0.dev", "opentelemetry-instrumentation-aws-lambda==0.41b0.dev", "opentelemetry-instrumentation-boto==0.41b0.dev", diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 505b16709d..038d370f7b 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -170,6 +170,7 @@ }, } default_instrumentations = [ + "opentelemetry-instrumentation-asyncio==0.41b0.dev", "opentelemetry-instrumentation-aws-lambda==0.41b0.dev", "opentelemetry-instrumentation-dbapi==0.41b0.dev", "opentelemetry-instrumentation-logging==0.41b0.dev", From 56d0c02548e8646c45c2ada7a5564e73824b1e63 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 14:59:23 +0900 Subject: [PATCH 06/50] modify tox generate result --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 8341405ca7..11d60bcb01 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -47,7 +47,7 @@ Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/ [tool.hatch.version] path = "src/opentelemetry/instrumentation/asyncio/version.py" -[tool.hatch.build.targets.sdist +[tool.hatch.build.targets.sdist] include = [ "/src", "/tests", From 55f23257bf7070e30579ccff1459a7bccafe796a Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 15:28:16 +0900 Subject: [PATCH 07/50] add python version check --- .../pyproject.toml | 1 + .../instrumentation/asyncio/__init__.py | 32 +++++++++++++------ .../tests/test_asyncio_taskgroup.py | 2 +- .../tests/test_asyncio_to_thread.py | 7 ++-- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 11d60bcb01..058e756da9 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -36,6 +36,7 @@ test = [ "opentelemetry-test-utils == 0.41b0.dev", "pytest", "wrapt >= 1.0.0, < 2.0.0", + "pytest-asyncio", ] [project.entry-points.opentelemetry_instrumentor] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index 3ae18a4cc2..f6c2afd41b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -132,6 +132,10 @@ def uninstrument_gather(self): unwrap(asyncio, "gather") def instrument_to_thread(self): + # to_thread was added in Python 3.9 + if sys.version_info < (3, 9): + return + def wrap_to_thread(method, instance, args, kwargs): if args: first_arg = args[0] @@ -144,22 +148,30 @@ def wrap_to_thread(method, instance, args, kwargs): _wrap(asyncio, "to_thread", wrap_to_thread) def uninstrument_to_thread(self): + # to_thread was added in Python 3.9 + if sys.version_info < (3, 9): + return unwrap(asyncio, "to_thread") def instrument_taskgroup_create_task(self): - if sys.version_info >= (3, 11): - def wrap_taskgroup_create_task(method, instance, args, kwargs): - if args: - coro = args[0] - wrapped_coro = self.trace_coroutine(coro) - wrapped_args = (wrapped_coro,) + args[1:] - return method(*wrapped_args, **kwargs) + # TaskGroup.create_task was added in Python 3.11 + if sys.version_info < (3, 11): + return + + def wrap_taskgroup_create_task(method, instance, args, kwargs): + if args: + coro = args[0] + wrapped_coro = self.trace_coroutine(coro) + wrapped_args = (wrapped_coro,) + args[1:] + return method(*wrapped_args, **kwargs) - _wrap(asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task) + _wrap(asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task) def uninstrument_taskgroup_create_task(self): - if sys.version_info >= (3, 11): - unwrap(asyncio.TaskGroup, "create_task") + # TaskGroup.create_task was added in Python 3.11 + if sys.version_info < (3, 11): + return + unwrap(asyncio.TaskGroup, "create_task") def trace_func(self, func): """Trace a function.""" diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py index 33a2456f86..fb617770eb 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -38,6 +38,7 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() def test_task_group_create_task(self): + # TaskGroup is only available in Python 3.11+ async def main(): if py11: async with asyncio.TaskGroup() as tg: @@ -46,6 +47,5 @@ async def main(): asyncio.run(main()) spans = self.memory_exporter.get_finished_spans() - assert spans if py11: self.assertEqual(len(spans), 10) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index 04afb945ff..b52bec2ab2 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +import sys from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer @@ -32,6 +33,7 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() def test_to_thread(self): + # to_thread is only available in Python 3.9+ def multiply(x, y): return x * y @@ -41,5 +43,6 @@ async def to_thread(): asyncio.run(to_thread()) spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) - assert spans[0].name == "asyncio.to_thread_func-multiply" + if sys.version_info >= (3, 9): + self.assertEqual(len(spans), 1) + assert spans[0].name == "asyncio.to_thread_func-multiply" From d3facc4d27e30d9373ee6dc63ab54b894da90bbe Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 17:00:45 +0900 Subject: [PATCH 08/50] modify test code --- .../tests/common_test_func.py | 2 +- .../tests/test_asyncio_to_thread.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py index 570136f52f..20041c6309 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py @@ -16,7 +16,7 @@ async def async_func(): - await asyncio.sleep(1) + await asyncio.sleep(0.1) async def factorial(name, number): diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index b52bec2ab2..ae1c660ce5 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -34,15 +34,16 @@ def tearDown(self): def test_to_thread(self): # to_thread is only available in Python 3.9+ - def multiply(x, y): - return x * y + if sys.version_info >= (3, 9): + def multiply(x, y): + return x * y - async def to_thread(): - result = await asyncio.to_thread(multiply, 2, 3) - assert result == 6 + async def to_thread(): + result = await asyncio.to_thread(multiply, 2, 3) + assert result == 6 + + asyncio.run(to_thread()) + spans = self.memory_exporter.get_finished_spans() - asyncio.run(to_thread()) - spans = self.memory_exporter.get_finished_spans() - if sys.version_info >= (3, 9): self.assertEqual(len(spans), 1) assert spans[0].name == "asyncio.to_thread_func-multiply" From 31b61573c0a7cc060fb5732453a457a683bc8d8c Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 11 Sep 2023 22:14:00 +0900 Subject: [PATCH 09/50] add CHANGELOG.md --- CHANGELOG.md | 5 +++++ .../src/opentelemetry/instrumentation/asyncio/version.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d56bcc43b..1e17635c6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added +- `opentelemetry-instrumentation-asyncio` Add support for asyncio + ([#1919](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1943)) + + ### Fixed - `opentelemetry-instrumentation-asgi` Fix UnboundLocalError local variable 'start' referenced before assignment diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py index 7f88144cf6..c2996671d6 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.41b0.dev" +__version__ = "0.42b0.dev" From 357453af127a4b230cfa4ca19c95bab38ff8d9cd Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 13 Sep 2023 00:14:05 +0900 Subject: [PATCH 10/50] add docs --- docs/instrumentation/asyncio/asyncio.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/instrumentation/asyncio/asyncio.rst diff --git a/docs/instrumentation/asyncio/asyncio.rst b/docs/instrumentation/asyncio/asyncio.rst new file mode 100644 index 0000000000..4cbcc70f09 --- /dev/null +++ b/docs/instrumentation/asyncio/asyncio.rst @@ -0,0 +1,7 @@ +OpenTelemetry asyncio Instrumentation +============================================== + +.. automodule:: opentelemetry.instrumentation.asyncio + :members: + :undoc-members: + :show-inheritance: From 77469d9689bbbf7c2cefa85eafaf3982e44a3871 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 13 Sep 2023 09:32:13 +0900 Subject: [PATCH 11/50] modify pyproject.toml --- opentelemetry-contrib-instrumentations/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index 03dae97826..233e656264 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ "opentelemetry-instrumentation-aiohttp-client==0.42b0.dev", "opentelemetry-instrumentation-aiopg==0.42b0.dev", "opentelemetry-instrumentation-asgi==0.42b0.dev", - "opentelemetry-instrumentation-asgi==0.42b0.dev", + "opentelemetry-instrumentation-asyncio==0.42b0.dev", "opentelemetry-instrumentation-asyncpg==0.42b0.dev", "opentelemetry-instrumentation-aws-lambda==0.42b0.dev", "opentelemetry-instrumentation-boto==0.42b0.dev", From 5e8b7abac604f59e5410c63d4c19207bb82b1121 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 13 Sep 2023 10:21:24 +0900 Subject: [PATCH 12/50] modify pyproject.toml --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 058e756da9..c168db17d7 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ instruments = [] test = [ "opentelemetry-instrumentation-asyncio[instruments]", - "opentelemetry-test-utils == 0.41b0.dev", + "opentelemetry-test-utils == 0.41b0", "pytest", "wrapt >= 1.0.0, < 2.0.0", "pytest-asyncio", From 61f2c85814f210ec69c814c43feab74b9b11acc9 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 16 Sep 2023 23:46:24 +0900 Subject: [PATCH 13/50] Add comments mentioned in an issue #1919 --- .../README.rst | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index c709513877..c00ef24336 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -6,7 +6,42 @@ OpenTelemetry asyncio Instrumentation .. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-asyncio.svg :target: https://pypi.org/project/opentelemetry-instrumentation-asyncio/ -This library allows tracing requests made by the asyncio library. +AsyncioInstrumentor: Tracing Requests Made by the Asyncio Library + +Primary Use Case: +----------------- +1. Performance and Error Monitoring: +The AsyncioInstrumentor tool offers significant advantages for developers and system administrators. It's designed to monitor real-time performance bottlenecks and catch exceptions within specific asynchronous tasks. + +When It's Not Ideal to Use AsyncioInstrumentor: +------------------------------------------------ +1. Frameworks with Built-in Instrumentation: +If you're utilizing a framework like aiohttp that already includes built-in instrumentation, you might not need this library. In such cases, leveraging the built-in tools of the framework is generally more beneficial than using external ones like AsyncioInstrumentor. + +2. Libraries Lacking Instrumentation: +Should you employ a library that isn't inherently instrumented, AsyncioInstrumentor can step in to fill that gap. + +3. Concerns about Overhead: +Tracing each task and future consistently can lead to added overhead. As a best practice, it's wise to enable tracing only when crucial, especially during the development stage. + +Example +------- +.. code:: python + + from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + AsyncioInstrumentor().instrument() + + import asyncio + + async def main(): + await asyncio.sleep(0.1) + + asyncio.run(main()) + +API +--- + + Installation ------------ From 5e522e23ae346afa4ef78c510415a96262e36f2d Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 16 Sep 2023 23:52:20 +0900 Subject: [PATCH 14/50] Add comments mentioned in an issue #1919 --- .../opentelemetry-instrumentation-asyncio/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index c00ef24336..5749379690 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -34,7 +34,7 @@ Example import asyncio async def main(): - await asyncio.sleep(0.1) + await asyncio.create_task(asyncio.sleep(0.1)) asyncio.run(main()) From 1859cb8af33dc75b3c7308b08b370338a0244aaa Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Mon, 2 Oct 2023 00:12:27 +0900 Subject: [PATCH 15/50] add asyncio component owner --- .github/component_owners.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/component_owners.yml b/.github/component_owners.yml index e31fde9b48..3e8459ec59 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -67,3 +67,6 @@ components: instrumentation/opentelemetry-instrumentation-cassandra: - mattcontinisio + + instrumentation/opentelemetry-instrumentation-asyncio: + - bourbonkk From d342d8ce641b08e22ed597d858ed4e1c928250ad Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 01:26:58 +0900 Subject: [PATCH 16/50] - Add instrumentation-asyncio metric. - Configure coroutines/to_thread func to apply trace via environment variables. - Apply trace to future using a boolean environment variable. --- .../README.rst | 98 ++++- .../instrumentation/asyncio/__init__.py | 346 ++++++++++++++++-- .../asyncio/environment_variables.py | 28 ++ .../instrumentation/asyncio/metrics.py | 65 ++++ .../instrumentation/asyncio/utils.py | 53 +++ .../tests/test_asyncio_cancellation.py | 33 +- .../tests/test_asyncio_create_task.py | 13 + .../tests/test_asyncio_ensure_future.py | 58 ++- .../tests/test_asyncio_gather.py | 8 + .../tests/test_asyncio_integration.py | 9 +- .../test_asyncio_run_coroutine_threadsafe.py | 8 + .../tests/test_asyncio_taskgroup.py | 24 +- .../tests/test_asyncio_to_thread.py | 28 +- .../tests/test_asyncio_utils.py | 41 +++ .../tests/test_asyncio_wait.py | 7 + 15 files changed, 743 insertions(+), 76 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py create mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 5749379690..35934f937c 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -8,36 +8,104 @@ OpenTelemetry asyncio Instrumentation AsyncioInstrumentor: Tracing Requests Made by the Asyncio Library -Primary Use Case: ------------------ -1. Performance and Error Monitoring: -The AsyncioInstrumentor tool offers significant advantages for developers and system administrators. It's designed to monitor real-time performance bottlenecks and catch exceptions within specific asynchronous tasks. -When It's Not Ideal to Use AsyncioInstrumentor: ------------------------------------------------- -1. Frameworks with Built-in Instrumentation: -If you're utilizing a framework like aiohttp that already includes built-in instrumentation, you might not need this library. In such cases, leveraging the built-in tools of the framework is generally more beneficial than using external ones like AsyncioInstrumentor. +The opentelemetry-instrumentation-asycnio package allows tracing asyncio applications. +The metric for coroutine, future, is generated even if there is no setting to generate a span. -2. Libraries Lacking Instrumentation: -Should you employ a library that isn't inherently instrumented, AsyncioInstrumentor can step in to fill that gap. -3. Concerns about Overhead: -Tracing each task and future consistently can lead to added overhead. As a best practice, it's wise to enable tracing only when crucial, especially during the development stage. +Set the name of the coroutine you want to trace. +----------------------------------------------- +.. code:: + export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 -Example -------- +If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. +---- +.. code:: + export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 + +For future, set it up like this +---- +.. code:: + export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true + +Run instrumented taskcoroutine +---- +1. coroutine +---- .. code:: python + # export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=sleep + + import asyncio from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + AsyncioInstrumentor().instrument() + async def main(): + await asyncio.create_task(asyncio.sleep(0.1)) + + asyncio.run(main()) + +2. future +---- +.. code:: python + + # export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true + + loop = asyncio.get_event_loop() + + future = asyncio.Future() + future.set_result(1) + task = asyncio.ensure_future(future) + loop.run_until_complete(task) + +3. to_thread +---- +.. code:: python + + # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func + import asyncio + from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + AsyncioInstrumentor().instrument() async def main(): - await asyncio.create_task(asyncio.sleep(0.1)) + await asyncio.to_thread(func) + + def func(): + pass asyncio.run(main()) + +asyncio metric types +------- + +* `asyncio.futures.duration` (ms) - Duration of the future +* `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future +* `asyncio.futures.cancelled` (count) - Number of futures cancelled +* `asyncio.futures.created` (count) - Number of futures created +* `asyncio.futures.active` (count) - Number of futures active +* `asyncio.futures.finished` (count) - Number of futures finished +* `asyncio.futures.timeouts` (count) - Number of futures timed out + +* `asyncio.coroutine.duration` (ms) - Duration of the coroutine +* `asyncio.coroutine.exceptions` (count) - Number of exceptions raised by the coroutine +* `asyncio.coroutine.created` (count) - Number of coroutines created +* `asyncio.coroutine.active` (count) - Number of coroutines active +* `asyncio.coroutine.finished` (count) - Number of coroutines finished +* `asyncio.coroutine.timeouts` (count) - Number of coroutines timed out +* `asyncio.coroutine.cancelled` (count) - Number of coroutines cancelled + +* `asyncio.to_thread.duration` (ms) - Duration of the to_thread +* `asyncio.to_thread.exceptions` (count) - Number of exceptions raised by the to_thread +* `asyncio.to_thread.created` (count) - Number of to_thread created +* `asyncio.to_thread.active` (count) - Number of to_thread active +* `asyncio.to_thread.finished` (count) - Number of to_thread finished + + + API --- diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index f6c2afd41b..dc0643c9f0 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -14,10 +14,32 @@ """ .. asyncio: https://github.com/python/asyncio -Usage ------ +The opentelemetry-instrumentation-asycnio package allows tracing asyncio applications. +The metric for coroutine, future, is generated even if there is no setting to generate a span. -.. code-block:: python + +Set the name of the coroutine you want to trace. +----------------------------------------------- +.. code:: + export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 + +If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. +---- +.. code:: + export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 + +For future, set it up like this +---- +.. code:: + export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true + +Run instrumented taskcoroutine +---- +1. coroutine +---- +.. code:: python + + # export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=sleep import asyncio from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor @@ -29,19 +51,83 @@ async def main(): asyncio.run(main()) +2. future +---- +.. code:: python + + # export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true + + loop = asyncio.get_event_loop() + + future = asyncio.Future() + future.set_result(1) + task = asyncio.ensure_future(future) + loop.run_until_complete(task) + +3. to_thread +---- +.. code:: python + + # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func + + import asyncio + from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor + + AsyncioInstrumentor().instrument() + + async def main(): + await asyncio.to_thread(func) + + def func(): + pass + + asyncio.run(main()) + + +asyncio metric types +------- + +* `asyncio.futures.duration` (ms) - Duration of the future +* `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future +* `asyncio.futures.cancelled` (count) - Number of futures cancelled +* `asyncio.futures.created` (count) - Number of futures created +* `asyncio.futures.active` (count) - Number of futures active +* `asyncio.futures.finished` (count) - Number of futures finished +* `asyncio.futures.timeouts` (count) - Number of futures timed out + +* `asyncio.coroutine.duration` (ms) - Duration of the coroutine +* `asyncio.coroutine.exceptions` (count) - Number of exceptions raised by the coroutine +* `asyncio.coroutine.created` (count) - Number of coroutines created +* `asyncio.coroutine.active` (count) - Number of coroutines active +* `asyncio.coroutine.finished` (count) - Number of coroutines finished +* `asyncio.coroutine.timeouts` (count) - Number of coroutines timed out +* `asyncio.coroutine.cancelled` (count) - Number of coroutines cancelled + +* `asyncio.to_thread.duration` (ms) - Duration of the to_thread +* `asyncio.to_thread.exceptions` (count) - Number of exceptions raised by the to_thread +* `asyncio.to_thread.created` (count) - Number of to_thread created +* `asyncio.to_thread.active` (count) - Number of to_thread active +* `asyncio.to_thread.finished` (count) - Number of to_thread finished + + API --- """ import asyncio import sys from asyncio import futures +from timeit import default_timer from typing import Collection +from opentelemetry.metrics import get_meter from opentelemetry.trace import get_tracer from opentelemetry.trace.status import Status, StatusCode from wrapt import wrap_function_wrapper as _wrap +from opentelemetry.instrumentation.asyncio.metrics import * from opentelemetry.instrumentation.asyncio.package import _instruments +from opentelemetry.instrumentation.asyncio.utils import get_coros_to_trace, get_future_trace_enabled, \ + get_to_thread_to_trace from opentelemetry.instrumentation.asyncio.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import unwrap @@ -67,7 +153,33 @@ class AsyncioInstrumentor(BaseInstrumentor): def __init__(self): super().__init__() + self.to_thread_duration_metric = None + self.to_thread_exception_metric = None + self.to_thread_active_metric = None + self.to_thread_created_metric = None + self.to_thread_finished_metric = None + + self.coro_duration_metric = None + self.coro_exception_metric = None + self.coro_cancelled_metric = None + self.coro_active_metric = None + self.coro_created_metric = None + self.coro_finished_metric = None + self.coro_timeout_metric = None + + self.future_duration_metric = None + self.future_exception_metric = None + self.future_cancelled_metric = None + self.future_active_metric = None + self.future_created_metric = None + self.future_finished_metric = None + self.future_timeout_metric = None + self._tracer = None + self._meter = None + self._coros_name_to_trace: set = set() + self._to_thread_name_to_trace: set = set() + self._future_active_enabled: bool = False def instrumentation_dependencies(self) -> Collection[str]: return _instruments @@ -77,6 +189,18 @@ def _instrument(self, **kwargs): self._tracer = get_tracer( __name__, __version__, tracer_provider ) + self._meter = get_meter( + __name__, __version__, kwargs.get("meter_provider") + ) + + self._coros_name_to_trace = get_coros_to_trace() + self._future_active_enabled = get_future_trace_enabled() + self._to_thread_name_to_trace = get_to_thread_to_trace() + + self.create_coro_metric() + self.create_future_metric() + self.create_to_thread_metric() + for method in self.methods_with_coroutine: self.instrument_method_with_coroutine(method) @@ -140,7 +264,7 @@ def wrap_to_thread(method, instance, args, kwargs): if args: first_arg = args[0] # Wrap the first argument - wrapped_first_arg = self.trace_func(first_arg) + wrapped_first_arg = self.trace_to_thread(first_arg) wrapped_args = (wrapped_first_arg,) + args[1:] return method(*wrapped_args, **kwargs) @@ -173,15 +297,31 @@ def uninstrument_taskgroup_create_task(self): return unwrap(asyncio.TaskGroup, "create_task") - def trace_func(self, func): + def trace_to_thread(self, func): """Trace a function.""" - with self._tracer.start_as_current_span(f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__) as span: - try: - return func - except Exception as exc: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(exc) - raise + start = default_timer() + self.to_thread_created_metric.add(1) + self.to_thread_active_metric.add(1) + span = self._tracer.start_span( + f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__) if func.__name__ in self._to_thread_name_to_trace else None + exception = None + try: + return func + except Exception as exc: + exception_attr = {ASYNCIO_EXCEPTIONS_NAME: exc.__class__.__name__} + exception = exc + self.to_thread_exception_metric.add(1, exception_attr) + raise + finally: + duration = max(round((default_timer() - start) * 1000), 0) + self.to_thread_duration_metric.record(duration) + self.to_thread_finished_metric.add(1) + self.to_thread_active_metric.add(-1) + if span: + if span.is_recording() and exception: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exception) + span.end() def trace_item(self, coro_or_future): """Trace a coroutine or future item.""" @@ -195,39 +335,171 @@ def trace_item(self, coro_or_future): return coro_or_future async def trace_coroutine(self, coro): - - with self._tracer.start_as_current_span(f"{ASYNCIO_PREFIX}coro-" + coro.__name__) as span: - exception = None # Initialize the exception variable - try: - return await coro - # CancelledError is raised when a coroutine is cancelled - # before it has a chance to run. We don't want to record - # this as an error. - except asyncio.CancelledError: - pass - except (asyncio.TimeoutError, - asyncio.InvalidStateError, - asyncio.SendfileNotAvailableError, - asyncio.IncompleteReadError, - asyncio.LimitOverrunError, - asyncio.BrokenBarrierError, - Exception) as exc: # General exception should be the last - exception = exc - raise - finally: + start = default_timer() + coro_attr = { + ASYNCIO_COROUTINE_NAME: coro.__name__, + } + self.coro_created_metric.add(1, coro_attr) + self.coro_active_metric.add(1, coro_attr) + + span = self._tracer.start_span( + f"{ASYNCIO_PREFIX}coro-" + coro.__name__) if coro.__name__ in self._coros_name_to_trace else None + + exception = None + try: + return await coro + # CancelledError is raised when a coroutine is cancelled + # before it has a chance to run. We don't want to record + # this as an error. + except asyncio.CancelledError: + self.coro_cancelled_metric.add(1, coro_attr) + except asyncio.TimeoutError: + self.coro_timeout_metric.add(1, coro_attr) + raise + except Exception as exc: + exception = exc + coro_exception_attr = coro_attr.copy() + coro_exception_attr[ASYNCIO_EXCEPTIONS_NAME] = exc.__class__.__name__ + self.coro_exception_metric.add(1, coro_exception_attr) + raise + finally: + duration = max(round((default_timer() - start) * 1000), 0) + self.coro_duration_metric.record(duration, coro_attr) + self.coro_finished_metric.add(1, coro_attr) + self.coro_active_metric.add(-1, coro_attr) + + if span: if span.is_recording() and exception: span.set_status(Status(StatusCode.ERROR)) span.record_exception(exception) + span.end() def trace_future(self, future): - span = self._tracer.start_span(f"{ASYNCIO_PREFIX}" + future.__class__.__name__) + start = default_timer() + self.future_created_metric.add(1) + self.future_active_metric.add(1) + span = self._tracer.start_span(f"{ASYNCIO_PREFIX}future") if self._future_active_enabled else None def callback(f): exception = f.exception() - if exception: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(exception) - span.end() + if isinstance(exception, asyncio.CancelledError): + self.future_cancelled_metric.add(1) + elif isinstance(exception, asyncio.TimeoutError): + self.future_timeout_metric.add(1) + elif exception: + exception_attr = {ASYNCIO_EXCEPTIONS_NAME: exception.__class__.__name__} + self.future_exception_metric.add(1, exception_attr) + + duration = max(round((default_timer() - start) * 1000), 0) + self.future_duration_metric.record(duration) + self.future_finished_metric.add(1) + self.future_active_metric.add(-1) + if span: + if span.is_recording() and exception: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exception) + span.end() future.add_done_callback(callback) return future + + def create_coro_metric(self): + self.coro_duration_metric = self._meter.create_histogram( + name=ASYNCIO_COROUTINE_DURATION, + description="Duration of asyncio coroutine", + unit="ms", + ) + self.coro_exception_metric = self._meter.create_counter( + name=ASYNCIO_COROUTINE_EXCEPTIONS, + description="Number of exceptions in asyncio coroutine", + unit="1", + ) + self.coro_cancelled_metric = self._meter.create_counter( + name=ASYNCIO_COROUTINE_CANCELLED, + description="Number of asyncio coroutine cancelled", + unit="1", + ) + self.coro_active_metric = self._meter.create_up_down_counter( + name=ASYNCIO_COROUTINE_ACTIVE, + description="Number of asyncio coroutine active", + unit="1", + ) + self.coro_created_metric = self._meter.create_counter( + name=ASYNCIO_COROUTINE_CREATED, + description="Number of asyncio coroutine created", + unit="1", + ) + self.coro_finished_metric = self._meter.create_counter( + name=ASYNCIO_COROUTINE_FINISHED, + description="Number of asyncio coroutine finished", + unit="1", + ) + self.coro_timeout_metric = self._meter.create_counter( + name=ASYNCIO_COROUTINE_TIMEOUTS, + description="Number of asyncio coroutine timeouts", + unit="1", + ) + + def create_future_metric(self): + self.future_duration_metric = self._meter.create_histogram( + name=ASYNCIO_FUTURES_DURATION, + description="Duration of asyncio future", + unit="ms", + ) + self.future_exception_metric = self._meter.create_counter( + name=ASYNCIO_FUTURES_EXCEPTIONS, + description="Number of exceptions in asyncio future", + unit="1", + ) + self.future_cancelled_metric = self._meter.create_counter( + name=ASYNCIO_FUTURES_CANCELLED, + description="Number of asyncio future cancelled", + unit="1", + ) + self.future_created_metric = self._meter.create_counter( + name=ASYNCIO_FUTURES_CREATED, + description="Number of asyncio future created", + unit="1", + ) + self.future_active_metric = self._meter.create_up_down_counter( + name=ASYNCIO_FUTURES_ACTIVE, + description="Number of asyncio future active", + unit="1", + ) + self.future_finished_metric = self._meter.create_counter( + name=ASYNCIO_FUTURES_FINISHED, + description="Number of asyncio future finished", + unit="1", + ) + self.future_timeout_metric = self._meter.create_counter( + name=ASYNCIO_FUTURES_TIMEOUTS, + description="Number of asyncio future timeouts", + unit="1", + ) + + def create_to_thread_metric(self): + self.to_thread_duration_metric = self._meter.create_histogram( + name=ASYNCIO_TO_THREAD_DURATION, + description="Duration of asyncio function", + unit="ms", + ) + self.to_thread_exception_metric = self._meter.create_counter( + name=ASYNCIO_TO_THREAD_EXCEPTIONS, + description="Number of exceptions in asyncio function", + unit="1", + ) + self.to_thread_created_metric = self._meter.create_counter( + name=ASYNCIO_TO_THREAD_CREATED, + description="Number of asyncio function created", + unit="1", + ) + self.to_thread_active_metric = self._meter.create_up_down_counter( + name=ASYNCIO_TO_THREAD_ACTIVE, + description="Number of asyncio function active", + unit="1", + ) + self.to_thread_finished_metric = self._meter.create_counter( + name=ASYNCIO_TO_THREAD_FINISHED, + description="Number of asyncio function finished", + unit="1", + ) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py new file mode 100644 index 0000000000..4e64eb5d73 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py @@ -0,0 +1,28 @@ +# 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. + +""" +Enter the names of the coroutines to be traced through the environment variable below, separated by commas. +""" +OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE = "OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE" + +""" +To determines whether the tracing feature for Future of Asyncio in Python is enabled or not. +""" +OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED = "OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED" + +""" +Enter the names of the functions to be traced through the environment variable below, separated by commas. +""" +OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE = "OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE" diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py new file mode 100644 index 0000000000..90551bf873 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py @@ -0,0 +1,65 @@ +# 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. + +ASYNCIO_COROUTINE_DURATION = "asyncio.coroutine.duration" +ASYNCIO_COROUTINE_EXCEPTIONS = "asyncio.coroutine.exceptions" +ASYNCIO_COROUTINE_CANCELLED = "asyncio.coroutine.cancelled" +ASYNCIO_COROUTINE_ACTIVE = "asyncio.coroutine.active" +ASYNCIO_COROUTINE_CREATED = "asyncio.coroutine.created" +ASYNCIO_COROUTINE_FINISHED = "asyncio.coroutine.finished" +ASYNCIO_COROUTINE_TIMEOUTS = "asyncio.coroutine.timeouts" + +ASYNCIO_COROUTINE_NAME = "coroutine.name" +ASYNCIO_EXCEPTIONS_NAME = "exceptions.name" + +ASYNCIO_FUTURES_DURATION = "asyncio.futures.duration" +ASYNCIO_FUTURES_EXCEPTIONS = "asyncio.futures.exceptions" +ASYNCIO_FUTURES_CANCELLED = "asyncio.futures.cancelled" +ASYNCIO_FUTURES_CREATED = "asyncio.futures.created" +ASYNCIO_FUTURES_ACTIVE = "asyncio.futures.active" +ASYNCIO_FUTURES_FINISHED = "asyncio.futures.finished" +ASYNCIO_FUTURES_TIMEOUTS = "asyncio.futures.timeouts" + +ASYNCIO_TO_THREAD_DURATION = "asyncio.to_thread.duration" +ASYNCIO_TO_THREAD_EXCEPTIONS = "asyncio.to_thread.exceptions" +ASYNCIO_TO_THREAD_CREATED = "asyncio.to_thread.created" +ASYNCIO_TO_THREAD_ACTIVE = "asyncio.to_thread.active" +ASYNCIO_TO_THREAD_FINISHED = "asyncio.to_thread.finished" + +__all__ = [ + "ASYNCIO_COROUTINE_DURATION", + "ASYNCIO_COROUTINE_EXCEPTIONS", + "ASYNCIO_COROUTINE_CANCELLED", + "ASYNCIO_COROUTINE_ACTIVE", + "ASYNCIO_COROUTINE_CREATED", + "ASYNCIO_COROUTINE_FINISHED", + "ASYNCIO_COROUTINE_TIMEOUTS", + + "ASYNCIO_COROUTINE_NAME", + "ASYNCIO_EXCEPTIONS_NAME", + + "ASYNCIO_FUTURES_DURATION", + "ASYNCIO_FUTURES_EXCEPTIONS", + "ASYNCIO_FUTURES_CANCELLED", + "ASYNCIO_FUTURES_CREATED", + "ASYNCIO_FUTURES_ACTIVE", + "ASYNCIO_FUTURES_FINISHED", + "ASYNCIO_FUTURES_TIMEOUTS", + + "ASYNCIO_TO_THREAD_DURATION", + "ASYNCIO_TO_THREAD_EXCEPTIONS", + "ASYNCIO_TO_THREAD_CREATED", + "ASYNCIO_TO_THREAD_ACTIVE", + "ASYNCIO_TO_THREAD_FINISHED", +] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py new file mode 100644 index 0000000000..133c4ad47a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -0,0 +1,53 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, \ + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE + + +def separate_coro_names_by_comma(coro_names) -> set: + """ + Function to separate the coroutines to be traced by comma + """ + if coro_names is None: + return set() + return set(coro_name.strip() for coro_name in coro_names.split(",")) + + +def get_coros_to_trace() -> set: + """ + Function to get the coroutines to be traced from the environment variable + """ + coro_names = os.getenv(OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE) + return separate_coro_names_by_comma(coro_names) + + +def get_future_trace_enabled() -> bool: + """ + Function to get the future active enabled flag from the environment variable + default value is False + """ + return os.getenv(OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, "False").lower() == "true" + + +def get_to_thread_to_trace() -> set: + """ + Function to get the functions to be traced from the environment variable + """ + func_names = os.getenv(OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE) + return separate_coro_names_by_comma(func_names) + + +__all__ = ["get_coros_to_trace", "get_future_trace_enabled", "get_to_thread_to_trace"] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index c8419ecc02..9829db50a4 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -12,15 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +from unittest.mock import patch from opentelemetry.test.test_base import TestBase -from opentelemetry.trace import get_tracer +from opentelemetry.trace import get_tracer, SpanKind +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor, ASYNCIO_COROUTINE_CANCELLED, \ + ASYNCIO_COROUTINE_DURATION, ASYNCIO_COROUTINE_ACTIVE, ASYNCIO_COROUTINE_CREATED, ASYNCIO_COROUTINE_FINISHED +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import cancellation_create_task -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor class TestAsyncioCancel(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "cancellation_coro, cancellable_coroutine" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() @@ -33,6 +41,23 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() def test_cancel(self): - asyncio.run(cancellation_create_task()) + with self._tracer.start_as_current_span("root", kind=SpanKind.SERVER): + asyncio.run(cancellation_create_task()) spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 2) + self.assertEqual(len(spans), 3) + self.assertEqual(spans[0].context.trace_id, spans[1].context.trace_id) + self.assertEqual(spans[2].context.trace_id, spans[1].context.trace_id) + + self.assertEqual(spans[0].name, 'asyncio.coro-cancellable_coroutine') + self.assertEqual(spans[1].name, 'asyncio.coro-cancellation_coro') + for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + if metric.name == ASYNCIO_COROUTINE_CANCELLED: + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == ASYNCIO_COROUTINE_DURATION: + self.assertNotEquals(metric.data.data_points[0].min, 0) + elif metric.name == ASYNCIO_COROUTINE_ACTIVE: + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == ASYNCIO_COROUTINE_CREATED: + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == ASYNCIO_COROUTINE_FINISHED: + self.assertEqual(metric.data.data_points[0].value, 1) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py index 5d1edb40a2..c98f405759 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -12,14 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer +from common_test_func import factorial from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE class TestAsyncioCreateTask(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() @@ -34,7 +42,12 @@ def tearDown(self): def test_asyncio_create_task(self): async def async_func(): await asyncio.create_task(asyncio.sleep(0)) + await asyncio.create_task(factorial("A", 3)) asyncio.run(async_func()) spans = self.memory_exporter.get_finished_spans() + """ + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" + """ self.assertEqual(len(spans), 1) + self.assertEqual(spans[0].name, "asyncio.coro-sleep") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index 42ed1a1c29..b45d768aea 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -12,16 +12,36 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +from unittest.mock import patch import pytest +from opentelemetry.sdk.metrics._internal.point import HistogramDataPoint, NumberDataPoint from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor, ASYNCIO_FUTURES_DURATION, \ + ASYNCIO_FUTURES_CANCELLED, ASYNCIO_FUTURES_CREATED, ASYNCIO_FUTURES_ACTIVE, ASYNCIO_FUTURES_EXCEPTIONS, \ + ASYNCIO_FUTURES_FINISHED, ASYNCIO_FUTURES_TIMEOUTS +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED from .common_test_func import async_func +_expected_metric_names = [ + ASYNCIO_FUTURES_DURATION, + ASYNCIO_FUTURES_EXCEPTIONS, + ASYNCIO_FUTURES_CANCELLED, + ASYNCIO_FUTURES_CREATED, + ASYNCIO_FUTURES_ACTIVE, + ASYNCIO_FUTURES_FINISHED, + ASYNCIO_FUTURES_TIMEOUTS +] + class TestAsyncioEnsureFuture(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() @@ -35,23 +55,41 @@ def tearDown(self): @pytest.mark.asyncio def test_asyncio_loop_ensure_future(self): + """ + async_func is not traced because it is not set in the environment variable + """ loop = asyncio.get_event_loop() task = asyncio.ensure_future(async_func()) loop.run_until_complete(task) spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) - self.assertEqual(spans[0].name, "asyncio.coro-async_func") + self.assertEqual(len(spans), 0) @pytest.mark.asyncio def test_asyncio_ensure_future_with_future(self): - loop = asyncio.get_event_loop() + with self._tracer.start_as_current_span("root") as root: + loop = asyncio.get_event_loop() - future = asyncio.Future() - future.set_result(1) - task = asyncio.ensure_future(future) - loop.run_until_complete(task) + future = asyncio.Future() + future.set_result(1) + task = asyncio.ensure_future(future) + loop.run_until_complete(task) spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) - self.assertEqual(spans[0].name, "asyncio.Future") + self.assertEqual(len(spans), 2) + self.assertEqual(spans[0].name, "asyncio.future") + for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + if metric.name == ASYNCIO_FUTURES_DURATION: + self.assertEquals(metric.data.data_points[0].count, 1) + elif metric.name == ASYNCIO_FUTURES_ACTIVE: + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == ASYNCIO_FUTURES_CREATED: + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == ASYNCIO_FUTURES_FINISHED: + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == ASYNCIO_FUTURES_EXCEPTIONS: + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == ASYNCIO_FUTURES_CANCELLED: + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == ASYNCIO_FUTURES_TIMEOUTS: + self.assertEqual(metric.data.data_points[0].value, 0) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py index ea02612893..1881f6b003 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -12,15 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import factorial from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor class TestAsyncioGather(TestBase): + + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "factorial" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py index b10a327bc6..25bbd68f3f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py @@ -12,12 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from .common_test_func import ensure_future from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE +from .common_test_func import ensure_future class TestAsyncioInstrumentor(TestBase): @@ -30,6 +32,11 @@ def setUp(self): def tearDown(self): super().tearDown() + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" + } + ) def test_asyncio_integration(self): AsyncioInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py index 000168509f..573da05c2e 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py @@ -14,14 +14,22 @@ import asyncio import threading from concurrent.futures import ThreadPoolExecutor +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE class TestRunCoroutineThreadSafe(TestBase): + + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "coro" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py index fb617770eb..f063a09fbd 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -13,11 +13,13 @@ # limitations under the License. import asyncio import sys +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import async_func py11 = False @@ -26,6 +28,11 @@ class TestAsyncioTaskgroup(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() @@ -39,13 +46,16 @@ def tearDown(self): def test_task_group_create_task(self): # TaskGroup is only available in Python 3.11+ + if not py11: + return + async def main(): - if py11: - async with asyncio.TaskGroup() as tg: - for _ in range(10): - tg.create_task(async_func()) + async with asyncio.TaskGroup() as tg: + for _ in range(10): + tg.create_task(async_func()) - asyncio.run(main()) + with self._tracer.start_as_current_span("root"): + asyncio.run(main()) spans = self.memory_exporter.get_finished_spans() - if py11: - self.assertEqual(len(spans), 10) + self.assertEqual(len(spans), 11) + self.assertEqual(spans[4].context.trace_id, spans[5].context.trace_id) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index ae1c660ce5..c62cfdff35 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -13,14 +13,22 @@ # limitations under the License. import asyncio import sys +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import \ + OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE class TestAsyncioToThread(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE: "multiply" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() @@ -42,8 +50,24 @@ async def to_thread(): result = await asyncio.to_thread(multiply, 2, 3) assert result == 6 - asyncio.run(to_thread()) + with self._tracer.start_as_current_span("root"): + asyncio.run(to_thread()) spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) + self.assertEqual(len(spans), 2) assert spans[0].name == "asyncio.to_thread_func-multiply" + for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + if metric.name == "asyncio.to_thread.duration": + self.assertEquals(metric.data.data_points[0].count, 1) + elif metric.name == "asyncio.to_thread.active": + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == "asyncio.to_thread.created": + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == "asyncio.to_thread.finished": + self.assertEqual(metric.data.data_points[0].value, 1) + elif metric.name == "asyncio.to_thread.exceptions": + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == "asyncio.to_thread.cancelled": + self.assertEqual(metric.data.data_points[0].value, 0) + elif metric.name == "asyncio.to_thread.name": + self.assertEqual(metric.data.data_points[0].value, "multiply") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py new file mode 100644 index 0000000000..f1749d8401 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py @@ -0,0 +1,41 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from unittest import TestCase +from unittest.mock import patch + +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, \ + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED + + +class TestAsyncioToThread(TestCase): + + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "test1,test2,test3 ,test4" + } + ) + def test_separator(self): + from opentelemetry.instrumentation.asyncio.utils import get_coros_to_trace + self.assertEqual( + get_coros_to_trace(), {"test1", "test2", "test3", "test4"} + ) + + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true" + } + ) + def test_future_trace_enabled(self): + from opentelemetry.instrumentation.asyncio.utils import get_future_trace_enabled + self.assertEqual(get_future_trace_enabled(), True) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py index 070617ca94..b03d9b1652 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py @@ -13,15 +13,22 @@ # limitations under the License. import asyncio import sys +from unittest.mock import patch from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer +from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import async_func from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor class TestAsyncioWait(TestBase): + @patch.dict( + "os.environ", { + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func" + } + ) def setUp(self): super().setUp() AsyncioInstrumentor().instrument() From 3adc0cd9f7cd65a2df05b241c5891b2d415b149f Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 01:46:47 +0900 Subject: [PATCH 17/50] modify docs --- .../README.rst | 16 ++++++++-------- .../instrumentation/asyncio/__init__.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 35934f937c..6d7fbe2564 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -19,19 +19,19 @@ Set the name of the coroutine you want to trace. export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ----- +----------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 For future, set it up like this ----- +----------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true -Run instrumented taskcoroutine ----- +Run instrumented application +-------------------- 1. coroutine ----- +-------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=sleep @@ -47,7 +47,7 @@ Run instrumented taskcoroutine asyncio.run(main()) 2. future ----- +-------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true @@ -60,7 +60,7 @@ Run instrumented taskcoroutine loop.run_until_complete(task) 3. to_thread ----- +-------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func @@ -80,7 +80,7 @@ Run instrumented taskcoroutine asyncio metric types -------- +-------------------- * `asyncio.futures.duration` (ms) - Duration of the future * `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index dc0643c9f0..4c7bf652c2 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -24,19 +24,19 @@ export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ----- +----------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 For future, set it up like this ----- +----------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true -Run instrumented taskcoroutine ----- +Run instrumented application +----------------------------------------------- 1. coroutine ----- +----------------------------------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=sleep @@ -52,7 +52,7 @@ async def main(): asyncio.run(main()) 2. future ----- +----------------------------------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true @@ -65,7 +65,7 @@ async def main(): loop.run_until_complete(task) 3. to_thread ----- +----------------------------------------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func @@ -85,7 +85,7 @@ def func(): asyncio metric types -------- +----------------------------------------------- * `asyncio.futures.duration` (ms) - Duration of the future * `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future From a56cd65137db5e5d142e962f3f8d886ea909523c Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 01:53:57 +0900 Subject: [PATCH 18/50] modify docs --- .../opentelemetry-instrumentation-asyncio/README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 6d7fbe2564..ee5a28bf47 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -14,12 +14,12 @@ The metric for coroutine, future, is generated even if there is no setting to ge Set the name of the coroutine you want to trace. ------------------------------------------------ +------------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ------------------------------------------------ +--------------------------------------------------------------------------------------------------------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 @@ -29,7 +29,7 @@ For future, set it up like this export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true Run instrumented application --------------------- +----------------------------- 1. coroutine -------------------- .. code:: python @@ -80,7 +80,7 @@ Run instrumented application asyncio metric types --------------------- +---------------------- * `asyncio.futures.duration` (ms) - Duration of the future * `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future From 33569425cb639f19204c06f538bccb9e167ca57e Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 09:01:58 +0900 Subject: [PATCH 19/50] modify docs --- .../instrumentation/asyncio/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index 4c7bf652c2..ce545bacb3 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -19,24 +19,24 @@ Set the name of the coroutine you want to trace. ------------------------------------------------ +------------------------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ------------------------------------------------ +------------------------------------------------------------------------------------------------------------------------ .. code:: export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 For future, set it up like this ------------------------------------------------ +--------------------------------- .. code:: export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true Run instrumented application ------------------------------------------------ +------------------------------ 1. coroutine ------------------------------------------------ +---------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=sleep @@ -52,7 +52,7 @@ async def main(): asyncio.run(main()) 2. future ------------------------------------------------ +------------ .. code:: python # export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true @@ -65,7 +65,7 @@ async def main(): loop.run_until_complete(task) 3. to_thread ------------------------------------------------ +------------- .. code:: python # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func @@ -85,7 +85,7 @@ def func(): asyncio metric types ------------------------------------------------ +--------------------- * `asyncio.futures.duration` (ms) - Duration of the future * `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future From b4c453cdb6c958e015f26f166039ab4241bc5330 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 09:21:45 +0900 Subject: [PATCH 20/50] modify docs --- .../instrumentation/asyncio/__init__.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index ce545bacb3..a396a429d1 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -17,22 +17,6 @@ The opentelemetry-instrumentation-asycnio package allows tracing asyncio applications. The metric for coroutine, future, is generated even if there is no setting to generate a span. - -Set the name of the coroutine you want to trace. -------------------------------------------------- -.. code:: - export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 - -If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ------------------------------------------------------------------------------------------------------------------------- -.. code:: - export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 - -For future, set it up like this ---------------------------------- -.. code:: - export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true - Run instrumented application ------------------------------ 1. coroutine From bf76ff307e74c0d53f8b7a8422438488db4be6d5 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 09:32:56 +0900 Subject: [PATCH 21/50] modify docs --- .../instrumentation/asyncio/__init__.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index a396a429d1..43e24cfc93 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -71,27 +71,27 @@ def func(): asyncio metric types --------------------- -* `asyncio.futures.duration` (ms) - Duration of the future -* `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future -* `asyncio.futures.cancelled` (count) - Number of futures cancelled -* `asyncio.futures.created` (count) - Number of futures created -* `asyncio.futures.active` (count) - Number of futures active -* `asyncio.futures.finished` (count) - Number of futures finished -* `asyncio.futures.timeouts` (count) - Number of futures timed out - -* `asyncio.coroutine.duration` (ms) - Duration of the coroutine -* `asyncio.coroutine.exceptions` (count) - Number of exceptions raised by the coroutine -* `asyncio.coroutine.created` (count) - Number of coroutines created -* `asyncio.coroutine.active` (count) - Number of coroutines active -* `asyncio.coroutine.finished` (count) - Number of coroutines finished -* `asyncio.coroutine.timeouts` (count) - Number of coroutines timed out -* `asyncio.coroutine.cancelled` (count) - Number of coroutines cancelled - -* `asyncio.to_thread.duration` (ms) - Duration of the to_thread -* `asyncio.to_thread.exceptions` (count) - Number of exceptions raised by the to_thread -* `asyncio.to_thread.created` (count) - Number of to_thread created -* `asyncio.to_thread.active` (count) - Number of to_thread active -* `asyncio.to_thread.finished` (count) - Number of to_thread finished +* asyncio.futures.duration (ms) - Duration of the future +* asyncio.futures.exceptions (count) - Number of exceptions raised by the future +* asyncio.futures.cancelled (count) - Number of futures cancelled +* asyncio.futures.created (count) - Number of futures created +* asyncio.futures.active (count) - Number of futures active +* asyncio.futures.finished (count) - Number of futures finished +* asyncio.futures.timeouts (count) - Number of futures timed out + +* asyncio.coroutine.duration (ms) - Duration of the coroutine +* asyncio.coroutine.exceptions (count) - Number of exceptions raised by the coroutine +* asyncio.coroutine.created (count) - Number of coroutines created +* asyncio.coroutine.active (count) - Number of coroutines active +* asyncio.coroutine.finished (count) - Number of coroutines finished +* asyncio.coroutine.timeouts (count) - Number of coroutines timed out +* asyncio.coroutine.cancelled (count) - Number of coroutines cancelled + +* asyncio.to_thread.duration (ms) - Duration of the to_thread +* asyncio.to_thread.exceptions (count) - Number of exceptions raised by the to_thread +* asyncio.to_thread.created (count) - Number of to_thread created +* asyncio.to_thread.active (count) - Number of to_thread active +* asyncio.to_thread.finished (count) - Number of to_thread finished API From 15c0375fe64a3191411ddaddaef44f9187251c43 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 10:17:47 +0900 Subject: [PATCH 22/50] modify test_code --- .../tests/test_asyncio_ensure_future.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index b45d768aea..8b6030f3d3 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -54,26 +54,24 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() @pytest.mark.asyncio - def test_asyncio_loop_ensure_future(self): + async def test_asyncio_loop_ensure_future(self): """ async_func is not traced because it is not set in the environment variable """ - loop = asyncio.get_event_loop() task = asyncio.ensure_future(async_func()) - loop.run_until_complete(task) + await task spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) @pytest.mark.asyncio - def test_asyncio_ensure_future_with_future(self): + async def test_asyncio_ensure_future_with_future(self): with self._tracer.start_as_current_span("root") as root: - loop = asyncio.get_event_loop() future = asyncio.Future() future.set_result(1) task = asyncio.ensure_future(future) - loop.run_until_complete(task) + await task spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) From 9cce290e08baab3f00f55d3c152de4267df7b2ee Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 10:26:03 +0900 Subject: [PATCH 23/50] modify test_code --- .../tests/test_asyncio_ensure_future.py | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index 8b6030f3d3..1bf31c485e 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -15,7 +15,6 @@ from unittest.mock import patch import pytest -from opentelemetry.sdk.metrics._internal.point import HistogramDataPoint, NumberDataPoint from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer @@ -54,28 +53,39 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() @pytest.mark.asyncio - async def test_asyncio_loop_ensure_future(self): + def test_asyncio_loop_ensure_future(self): """ async_func is not traced because it is not set in the environment variable """ - task = asyncio.ensure_future(async_func()) - await task + + async def test(): + task = asyncio.ensure_future(async_func()) + await task + + asyncio.run(test()) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 0) @pytest.mark.asyncio - async def test_asyncio_ensure_future_with_future(self): - with self._tracer.start_as_current_span("root") as root: + def test_asyncio_ensure_future_with_future(self): + async def test(): + with self._tracer.start_as_current_span("root") as root: + future = asyncio.Future() + future.set_result(1) + task = asyncio.ensure_future(future) + await task - future = asyncio.Future() - future.set_result(1) - task = asyncio.ensure_future(future) - await task + asyncio.run(test()) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) - self.assertEqual(spans[0].name, "asyncio.future") + for span in spans: + if span.name == "root": + self.assertEqual(span.parent, None) + if span.name == "asyncio.future": + self.assertNotEquals(span.parent.trace_id, 0) + for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: if metric.name == ASYNCIO_FUTURES_DURATION: self.assertEquals(metric.data.data_points[0].count, 1) From 6975ab7e1230325e2531c2db8a58447626aafaaf Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 10 Oct 2023 11:01:36 +0900 Subject: [PATCH 24/50] modify test_code --- .../tests/test_asyncio_create_task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py index c98f405759..3bb59a40cc 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -17,7 +17,7 @@ from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from common_test_func import factorial +from .common_test_func import factorial from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE From 6bd4ace6ddef6841710bed05c22c2fdbc68f30a2 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 8 Nov 2023 22:48:54 +0900 Subject: [PATCH 25/50] modify asyncio version --- .../src/opentelemetry/instrumentation/asyncio/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py index c2996671d6..2e4aa8c751 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.42b0.dev" +__version__ = "0.43b0.dev" From 86f137c0276e01594c5eb704bce70606d10157ef Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 8 Nov 2023 22:53:24 +0900 Subject: [PATCH 26/50] modify asyncio version --- 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 b4e1db321e..b7f867710f 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ "opentelemetry-instrumentation-aiohttp-server==0.43b0.dev", "opentelemetry-instrumentation-aiopg==0.43b0.dev", "opentelemetry-instrumentation-asgi==0.43b0.dev", + "opentelemetry-instrumentation-asyncio==0.43b0.dev", "opentelemetry-instrumentation-asyncpg==0.43b0.dev", "opentelemetry-instrumentation-aws-lambda==0.43b0.dev", "opentelemetry-instrumentation-boto==0.43b0.dev", From 8b077af9bdfc43b44c26ac55514ffb3f89506dab Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 12:33:47 +0900 Subject: [PATCH 27/50] update dependency --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 4 ++-- .../src/opentelemetry/instrumentation/asyncio/version.py | 2 +- opentelemetry-contrib-instrumentations/pyproject.toml | 2 +- .../src/opentelemetry/instrumentation/bootstrap_gen.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index c168db17d7..7f31f08769 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ - "opentelemetry-api ~= 1.12", + "opentelemetry-api ~= 1.14", "wrapt >= 1.0.0, < 2.0.0", ] @@ -33,7 +33,7 @@ dependencies = [ instruments = [] test = [ "opentelemetry-instrumentation-asyncio[instruments]", - "opentelemetry-test-utils == 0.41b0", + "opentelemetry-test-utils == 0.43b0", "pytest", "wrapt >= 1.0.0, < 2.0.0", "pytest-asyncio", diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py index 2e4aa8c751..ff896307c3 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.43b0.dev" +__version__ = "0.44b0.dev" diff --git a/opentelemetry-contrib-instrumentations/pyproject.toml b/opentelemetry-contrib-instrumentations/pyproject.toml index dee63f48dc..aa5e3c5680 100644 --- a/opentelemetry-contrib-instrumentations/pyproject.toml +++ b/opentelemetry-contrib-instrumentations/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "opentelemetry-instrumentation-aiohttp-server==0.44b0.dev", "opentelemetry-instrumentation-aiopg==0.44b0.dev", "opentelemetry-instrumentation-asgi==0.44b0.dev", - "opentelemetry-instrumentation-asyncio==0.43b0.dev", + "opentelemetry-instrumentation-asyncio==0.44b0.dev", "opentelemetry-instrumentation-asyncpg==0.44b0.dev", "opentelemetry-instrumentation-aws-lambda==0.44b0.dev", "opentelemetry-instrumentation-boto==0.44b0.dev", diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index d1d6ab0859..f5a75f90bc 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -186,7 +186,7 @@ }, ] default_instrumentations = [ - "opentelemetry-instrumentation-asyncio==0.43b0.dev", + "opentelemetry-instrumentation-asyncio==0.44b0.dev", "opentelemetry-instrumentation-aws-lambda==0.44b0.dev", "opentelemetry-instrumentation-dbapi==0.44b0.dev", "opentelemetry-instrumentation-logging==0.44b0.dev", From 9259d72ae7c5f90d292b012970dc73e0ffc70249 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 15:32:25 +0900 Subject: [PATCH 28/50] modified lint results --- .../pyproject.toml | 4 +- .../instrumentation/asyncio/__init__.py | 82 ++++++++++++++----- .../asyncio/environment_variables.py | 12 ++- .../instrumentation/asyncio/metrics.py | 3 - .../instrumentation/asyncio/utils.py | 22 +++-- .../tests/__init__.py | 2 +- .../tests/common_test_func.py | 12 ++- .../tests/test_asyncio_cancellation.py | 34 +++++--- .../tests/test_asyncio_create_task.py | 12 +-- .../tests/test_asyncio_ensure_future.py | 33 +++++--- .../tests/test_asyncio_gather.py | 16 ++-- .../tests/test_asyncio_integration.py | 10 +-- .../test_asyncio_run_coroutine_threadsafe.py | 12 ++- .../tests/test_asyncio_taskgroup.py | 11 +-- .../tests/test_asyncio_to_thread.py | 25 ++++-- .../tests/test_asyncio_utils.py | 26 +++--- .../tests/test_asyncio_wait.py | 22 +++-- 17 files changed, 218 insertions(+), 120 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index 7f31f08769..c36f5d2edb 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -26,6 +26,9 @@ classifiers = [ ] dependencies = [ "opentelemetry-api ~= 1.14", + "opentelemetry-instrumentation == 0.44b0.dev", + "opentelemetry-semantic-conventions == 0.44b0.dev", + "opentelemetry-test-utils == 0.44b0.dev", "wrapt >= 1.0.0, < 2.0.0", ] @@ -33,7 +36,6 @@ dependencies = [ instruments = [] test = [ "opentelemetry-instrumentation-asyncio[instruments]", - "opentelemetry-test-utils == 0.43b0", "pytest", "wrapt >= 1.0.0, < 2.0.0", "pytest-asyncio", diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index 43e24cfc93..bf795b7e64 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -52,8 +52,6 @@ async def main(): ------------- .. code:: python - # export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func - import asyncio from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor @@ -103,18 +101,43 @@ def func(): from timeit import default_timer from typing import Collection -from opentelemetry.metrics import get_meter -from opentelemetry.trace import get_tracer -from opentelemetry.trace.status import Status, StatusCode from wrapt import wrap_function_wrapper as _wrap -from opentelemetry.instrumentation.asyncio.metrics import * +from opentelemetry.instrumentation.asyncio.metrics import ( + ASYNCIO_COROUTINE_ACTIVE, + ASYNCIO_COROUTINE_CANCELLED, + ASYNCIO_COROUTINE_CREATED, + ASYNCIO_COROUTINE_DURATION, + ASYNCIO_COROUTINE_EXCEPTIONS, + ASYNCIO_COROUTINE_FINISHED, + ASYNCIO_COROUTINE_NAME, + ASYNCIO_COROUTINE_TIMEOUTS, + ASYNCIO_EXCEPTIONS_NAME, + ASYNCIO_FUTURES_ACTIVE, + ASYNCIO_FUTURES_CANCELLED, + ASYNCIO_FUTURES_CREATED, + ASYNCIO_FUTURES_DURATION, + ASYNCIO_FUTURES_EXCEPTIONS, + ASYNCIO_FUTURES_FINISHED, + ASYNCIO_FUTURES_TIMEOUTS, + ASYNCIO_TO_THREAD_ACTIVE, + ASYNCIO_TO_THREAD_CREATED, + ASYNCIO_TO_THREAD_DURATION, + ASYNCIO_TO_THREAD_EXCEPTIONS, + ASYNCIO_TO_THREAD_FINISHED, +) from opentelemetry.instrumentation.asyncio.package import _instruments -from opentelemetry.instrumentation.asyncio.utils import get_coros_to_trace, get_future_trace_enabled, \ - get_to_thread_to_trace +from opentelemetry.instrumentation.asyncio.utils import ( + get_coros_to_trace, + get_future_trace_enabled, + get_to_thread_to_trace, +) from opentelemetry.instrumentation.asyncio.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.metrics import get_meter +from opentelemetry.trace import get_tracer +from opentelemetry.trace.status import Status, StatusCode ASYNCIO_PREFIX = "asyncio." @@ -170,9 +193,7 @@ def instrumentation_dependencies(self) -> Collection[str]: def _instrument(self, **kwargs): tracer_provider = kwargs.get("tracer_provider") - self._tracer = get_tracer( - __name__, __version__, tracer_provider - ) + self._tracer = get_tracer(__name__, __version__, tracer_provider) self._meter = get_meter( __name__, __version__, kwargs.get("meter_provider") ) @@ -211,11 +232,15 @@ def wrap_coro_or_future(method, instance, args, kwargs): if args and len(args) > 0: first_arg = args[0] # Check if it's a coroutine or future and wrap it - if asyncio.iscoroutine(first_arg) or futures.isfuture(first_arg): + if asyncio.iscoroutine(first_arg) or futures.isfuture( + first_arg + ): args = (self.trace_item(first_arg),) + args[1:] # Check if it's a list and wrap each item elif isinstance(first_arg, list): - args = ([self.trace_item(item) for item in first_arg],) + args[1:] + args = ( + [self.trace_item(item) for item in first_arg], + ) + args[1:] return method(*args, **kwargs) _wrap(asyncio, method_name, wrap_coro_or_future) @@ -227,7 +252,6 @@ def uninstrument_method_with_coroutine(self, method_name): unwrap(asyncio, method_name) def instrument_gather(self): - def wrap_coros_or_futures(method, instance, args, kwargs): if args and len(args) > 0: # Check if it's a coroutine or future and wrap it @@ -286,8 +310,13 @@ def trace_to_thread(self, func): start = default_timer() self.to_thread_created_metric.add(1) self.to_thread_active_metric.add(1) - span = self._tracer.start_span( - f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__) if func.__name__ in self._to_thread_name_to_trace else None + span = ( + self._tracer.start_span( + f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__ + ) + if func.__name__ in self._to_thread_name_to_trace + else None + ) exception = None try: return func @@ -326,8 +355,11 @@ async def trace_coroutine(self, coro): self.coro_created_metric.add(1, coro_attr) self.coro_active_metric.add(1, coro_attr) - span = self._tracer.start_span( - f"{ASYNCIO_PREFIX}coro-" + coro.__name__) if coro.__name__ in self._coros_name_to_trace else None + span = ( + self._tracer.start_span(f"{ASYNCIO_PREFIX}coro-" + coro.__name__) + if coro.__name__ in self._coros_name_to_trace + else None + ) exception = None try: @@ -343,7 +375,9 @@ async def trace_coroutine(self, coro): except Exception as exc: exception = exc coro_exception_attr = coro_attr.copy() - coro_exception_attr[ASYNCIO_EXCEPTIONS_NAME] = exc.__class__.__name__ + coro_exception_attr[ + ASYNCIO_EXCEPTIONS_NAME + ] = exc.__class__.__name__ self.coro_exception_metric.add(1, coro_exception_attr) raise finally: @@ -362,7 +396,11 @@ def trace_future(self, future): start = default_timer() self.future_created_metric.add(1) self.future_active_metric.add(1) - span = self._tracer.start_span(f"{ASYNCIO_PREFIX}future") if self._future_active_enabled else None + span = ( + self._tracer.start_span(f"{ASYNCIO_PREFIX}future") + if self._future_active_enabled + else None + ) def callback(f): exception = f.exception() @@ -371,7 +409,9 @@ def callback(f): elif isinstance(exception, asyncio.TimeoutError): self.future_timeout_metric.add(1) elif exception: - exception_attr = {ASYNCIO_EXCEPTIONS_NAME: exception.__class__.__name__} + exception_attr = { + ASYNCIO_EXCEPTIONS_NAME: exception.__class__.__name__ + } self.future_exception_metric.add(1, exception_attr) duration = max(round((default_timer() - start) * 1000), 0) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py index 4e64eb5d73..7420ea362f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/environment_variables.py @@ -15,14 +15,20 @@ """ Enter the names of the coroutines to be traced through the environment variable below, separated by commas. """ -OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE = "OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE" +OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE = ( + "OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE" +) """ To determines whether the tracing feature for Future of Asyncio in Python is enabled or not. """ -OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED = "OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED" +OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED = ( + "OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED" +) """ Enter the names of the functions to be traced through the environment variable below, separated by commas. """ -OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE = "OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE" +OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE = ( + "OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE" +) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py index 90551bf873..92f02b8788 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py @@ -45,10 +45,8 @@ "ASYNCIO_COROUTINE_CREATED", "ASYNCIO_COROUTINE_FINISHED", "ASYNCIO_COROUTINE_TIMEOUTS", - "ASYNCIO_COROUTINE_NAME", "ASYNCIO_EXCEPTIONS_NAME", - "ASYNCIO_FUTURES_DURATION", "ASYNCIO_FUTURES_EXCEPTIONS", "ASYNCIO_FUTURES_CANCELLED", @@ -56,7 +54,6 @@ "ASYNCIO_FUTURES_ACTIVE", "ASYNCIO_FUTURES_FINISHED", "ASYNCIO_FUTURES_TIMEOUTS", - "ASYNCIO_TO_THREAD_DURATION", "ASYNCIO_TO_THREAD_EXCEPTIONS", "ASYNCIO_TO_THREAD_CREATED", diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index 133c4ad47a..78d700fdff 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -13,8 +13,11 @@ # limitations under the License. import os -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, \ - OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, + OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE, +) def separate_coro_names_by_comma(coro_names) -> set: @@ -39,15 +42,24 @@ def get_future_trace_enabled() -> bool: Function to get the future active enabled flag from the environment variable default value is False """ - return os.getenv(OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, "False").lower() == "true" + return ( + os.getenv(OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, "False").lower() + == "true" + ) def get_to_thread_to_trace() -> set: """ Function to get the functions to be traced from the environment variable """ - func_names = os.getenv(OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE) + func_names = os.getenv( + OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE + ) return separate_coro_names_by_comma(func_names) -__all__ = ["get_coros_to_trace", "get_future_trace_enabled", "get_to_thread_to_trace"] +__all__ = [ + "get_coros_to_trace", + "get_future_trace_enabled", + "get_to_thread_to_trace", +] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py index eacf7c9c0e..b0a6f42841 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/__init__.py @@ -10,4 +10,4 @@ # 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. \ No newline at end of file +# limitations under the License. diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py index 20041c6309..ed8803a1f0 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py @@ -19,14 +19,12 @@ async def async_func(): await asyncio.sleep(0.1) -async def factorial(name, number): - f = 1 - for i in range(2, number + 1): - print(f"Task {name}: Compute factorial({number}), currently i={i}...") +async def factorial(number): + factorial_value = 1 + for value in range(2, number + 1): await asyncio.sleep(0) - f *= i - print(f"Task {name}: factorial({number}) = {f}") - return f + factorial_value *= value + return factorial_value async def cancellable_coroutine(): diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index 9829db50a4..ae887af44d 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -14,20 +14,29 @@ import asyncio from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import ( + ASYNCIO_COROUTINE_ACTIVE, + ASYNCIO_COROUTINE_CANCELLED, + ASYNCIO_COROUTINE_CREATED, + ASYNCIO_COROUTINE_DURATION, + ASYNCIO_COROUTINE_FINISHED, + AsyncioInstrumentor, +) +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase -from opentelemetry.trace import get_tracer, SpanKind +from opentelemetry.trace import SpanKind, get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor, ASYNCIO_COROUTINE_CANCELLED, \ - ASYNCIO_COROUTINE_DURATION, ASYNCIO_COROUTINE_ACTIVE, ASYNCIO_COROUTINE_CREATED, ASYNCIO_COROUTINE_FINISHED -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import cancellation_create_task class TestAsyncioCancel(TestBase): @patch.dict( - "os.environ", { + "os.environ", + { OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "cancellation_coro, cancellable_coroutine" - } + }, ) def setUp(self): super().setUp() @@ -48,13 +57,18 @@ def test_cancel(self): self.assertEqual(spans[0].context.trace_id, spans[1].context.trace_id) self.assertEqual(spans[2].context.trace_id, spans[1].context.trace_id) - self.assertEqual(spans[0].name, 'asyncio.coro-cancellable_coroutine') - self.assertEqual(spans[1].name, 'asyncio.coro-cancellation_coro') - for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + self.assertEqual(spans[0].name, "asyncio.coro-cancellable_coroutine") + self.assertEqual(spans[1].name, "asyncio.coro-cancellation_coro") + for metric in ( + self.memory_metrics_reader.get_metrics_data() + .resource_metrics[0] + .scope_metrics[0] + .metrics + ): if metric.name == ASYNCIO_COROUTINE_CANCELLED: self.assertEqual(metric.data.data_points[0].value, 1) elif metric.name == ASYNCIO_COROUTINE_DURATION: - self.assertNotEquals(metric.data.data_points[0].min, 0) + self.assertEqual(metric.data.data_points[0].min != 0, True) elif metric.name == ASYNCIO_COROUTINE_ACTIVE: self.assertEqual(metric.data.data_points[0].value, 0) elif metric.name == ASYNCIO_COROUTINE_CREATED: diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py index 3bb59a40cc..af62919156 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -14,19 +14,19 @@ import asyncio from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer from .common_test_func import factorial -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE class TestAsyncioCreateTask(TestBase): @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" - } + "os.environ", {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep"} ) def setUp(self): super().setUp() @@ -42,7 +42,7 @@ def tearDown(self): def test_asyncio_create_task(self): async def async_func(): await asyncio.create_task(asyncio.sleep(0)) - await asyncio.create_task(factorial("A", 3)) + await asyncio.create_task(factorial(3)) asyncio.run(async_func()) spans = self.memory_exporter.get_finished_spans() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index 1bf31c485e..f0d89aa00c 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -15,13 +15,23 @@ from unittest.mock import patch import pytest + +from opentelemetry.instrumentation.asyncio import ( + ASYNCIO_FUTURES_ACTIVE, + ASYNCIO_FUTURES_CANCELLED, + ASYNCIO_FUTURES_CREATED, + ASYNCIO_FUTURES_DURATION, + ASYNCIO_FUTURES_EXCEPTIONS, + ASYNCIO_FUTURES_FINISHED, + ASYNCIO_FUTURES_TIMEOUTS, + AsyncioInstrumentor, +) +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor, ASYNCIO_FUTURES_DURATION, \ - ASYNCIO_FUTURES_CANCELLED, ASYNCIO_FUTURES_CREATED, ASYNCIO_FUTURES_ACTIVE, ASYNCIO_FUTURES_EXCEPTIONS, \ - ASYNCIO_FUTURES_FINISHED, ASYNCIO_FUTURES_TIMEOUTS -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED from .common_test_func import async_func _expected_metric_names = [ @@ -31,15 +41,13 @@ ASYNCIO_FUTURES_CREATED, ASYNCIO_FUTURES_ACTIVE, ASYNCIO_FUTURES_FINISHED, - ASYNCIO_FUTURES_TIMEOUTS + ASYNCIO_FUTURES_TIMEOUTS, ] class TestAsyncioEnsureFuture(TestBase): @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true" - } + "os.environ", {OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true"} ) def setUp(self): super().setUp() @@ -70,7 +78,7 @@ async def test(): @pytest.mark.asyncio def test_asyncio_ensure_future_with_future(self): async def test(): - with self._tracer.start_as_current_span("root") as root: + with self._tracer.start_as_current_span("root"): future = asyncio.Future() future.set_result(1) task = asyncio.ensure_future(future) @@ -86,7 +94,12 @@ async def test(): if span.name == "asyncio.future": self.assertNotEquals(span.parent.trace_id, 0) - for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + for metric in ( + self.memory_metrics_reader.get_metrics_data() + .resource_metrics[0] + .scope_metrics[0] + .metrics + ): if metric.name == ASYNCIO_FUTURES_DURATION: self.assertEquals(metric.data.data_points[0].count, 1) elif metric.name == ASYNCIO_FUTURES_ACTIVE: diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py index 1881f6b003..209b8b34f1 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -14,20 +14,20 @@ import asyncio from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import factorial -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor class TestAsyncioGather(TestBase): - @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "factorial" - } + "os.environ", + {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "factorial"}, ) def setUp(self): super().setUp() @@ -43,9 +43,7 @@ def tearDown(self): def test_asyncio_gather(self): async def gather_factorial(): await asyncio.gather( - factorial("A", 2), - factorial("B", 3), - factorial("C", 4) + factorial(2), factorial(3), factorial(4) ) asyncio.run(gather_factorial()) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py index 25bbd68f3f..4070a29450 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py @@ -14,11 +14,13 @@ import asyncio from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import ensure_future @@ -33,9 +35,7 @@ def tearDown(self): super().tearDown() @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" - } + "os.environ", {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep"} ) def test_asyncio_integration(self): AsyncioInstrumentor().instrument() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py index 573da05c2e..0de870ec29 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py @@ -16,19 +16,17 @@ from concurrent.futures import ThreadPoolExecutor from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE - class TestRunCoroutineThreadSafe(TestBase): - @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "coro" - } + "os.environ", {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "coro"} ) def setUp(self): super().setUp() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py index f063a09fbd..f775efcdb4 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -15,11 +15,13 @@ import sys from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import async_func py11 = False @@ -29,9 +31,8 @@ class TestAsyncioTaskgroup(TestBase): @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func" - } + "os.environ", + {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func"}, ) def setUp(self): super().setUp() diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index c62cfdff35..fe494ebdaa 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -15,19 +15,18 @@ import sys from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor -from opentelemetry.instrumentation.asyncio.environment_variables import \ - OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE - class TestAsyncioToThread(TestBase): @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE: "multiply" - } + "os.environ", + {OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE: "multiply"}, ) def setUp(self): super().setUp() @@ -43,6 +42,7 @@ def tearDown(self): def test_to_thread(self): # to_thread is only available in Python 3.9+ if sys.version_info >= (3, 9): + def multiply(x, y): return x * y @@ -56,7 +56,12 @@ async def to_thread(): self.assertEqual(len(spans), 2) assert spans[0].name == "asyncio.to_thread_func-multiply" - for metric in self.memory_metrics_reader.get_metrics_data().resource_metrics[0].scope_metrics[0].metrics: + for metric in ( + self.memory_metrics_reader.get_metrics_data() + .resource_metrics[0] + .scope_metrics[0] + .metrics + ): if metric.name == "asyncio.to_thread.duration": self.assertEquals(metric.data.data_points[0].count, 1) elif metric.name == "asyncio.to_thread.active": @@ -70,4 +75,6 @@ async def to_thread(): elif metric.name == "asyncio.to_thread.cancelled": self.assertEqual(metric.data.data_points[0].value, 0) elif metric.name == "asyncio.to_thread.name": - self.assertEqual(metric.data.data_points[0].value, "multiply") + self.assertEqual( + metric.data.data_points[0].value, "multiply" + ) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py index f1749d8401..5e5efb0522 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py @@ -14,28 +14,34 @@ from unittest import TestCase from unittest.mock import patch -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, \ - OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, + OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, +) class TestAsyncioToThread(TestCase): - @patch.dict( - "os.environ", { + "os.environ", + { OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "test1,test2,test3 ,test4" - } + }, ) def test_separator(self): - from opentelemetry.instrumentation.asyncio.utils import get_coros_to_trace + from opentelemetry.instrumentation.asyncio.utils import ( + get_coros_to_trace, + ) + self.assertEqual( get_coros_to_trace(), {"test1", "test2", "test3", "test4"} ) @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true" - } + "os.environ", {OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true"} ) def test_future_trace_enabled(self): - from opentelemetry.instrumentation.asyncio.utils import get_future_trace_enabled + from opentelemetry.instrumentation.asyncio.utils import ( + get_future_trace_enabled, + ) + self.assertEqual(get_future_trace_enabled(), True) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py index b03d9b1652..f00c81310b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py @@ -15,19 +15,20 @@ import sys from unittest.mock import patch +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor +from opentelemetry.instrumentation.asyncio.environment_variables import ( + OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import get_tracer -from opentelemetry.instrumentation.asyncio.environment_variables import OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE from .common_test_func import async_func -from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor class TestAsyncioWait(TestBase): @patch.dict( - "os.environ", { - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func" - } + "os.environ", + {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "async_func"}, ) def setUp(self): super().setUp() @@ -41,12 +42,14 @@ def tearDown(self): AsyncioInstrumentor().uninstrument() def test_asyncio_wait_with_create_task(self): - async def main(): if sys.version_info >= (3, 11): # In Python 3.11, you can't send coroutines directly to asyncio.wait(). # Instead, you must wrap them in asyncio.create_task(). - tasks = [asyncio.create_task(async_func()), asyncio.create_task(async_func())] + tasks = [ + asyncio.create_task(async_func()), + asyncio.create_task(async_func()), + ] await asyncio.wait(tasks) else: await asyncio.wait([async_func(), async_func()]) @@ -69,7 +72,10 @@ async def main(): if sys.version_info >= (3, 11): # In Python 3.11, you can't send coroutines directly to asyncio.as_completed(). # Instead, you must wrap them in asyncio.create_task(). - tasks = [asyncio.create_task(async_func()), asyncio.create_task(async_func())] + tasks = [ + asyncio.create_task(async_func()), + asyncio.create_task(async_func()), + ] for task in asyncio.as_completed(tasks): await task else: From 05e6a745b7030522abd3f9c2b5a572b3e5d193e4 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 21:54:12 +0900 Subject: [PATCH 29/50] modified lint results --- .../tests/test_asyncio_gather.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py index 209b8b34f1..74909d26e1 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -42,9 +42,7 @@ def tearDown(self): def test_asyncio_gather(self): async def gather_factorial(): - await asyncio.gather( - factorial(2), factorial(3), factorial(4) - ) + await asyncio.gather(factorial(2), factorial(3), factorial(4)) asyncio.run(gather_factorial()) spans = self.memory_exporter.get_finished_spans() From 39d0a531c426af847fe047cbd81eed54edf5b878 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 22:53:01 +0900 Subject: [PATCH 30/50] modified lint results --- .../instrumentation/asyncio/__init__.py | 64 ++++++----- .../instrumentation/asyncio/utils.py | 1 + .../tests/test_asyncio_cancellation.py | 1 + .../tests/test_asyncio_create_task.py | 5 +- .../tests/test_asyncio_ensure_future.py | 5 +- .../tests/test_asyncio_gather.py | 1 + .../tests/test_asyncio_integration.py | 4 +- .../test_asyncio_run_coroutine_threadsafe.py | 1 + .../tests/test_asyncio_taskgroup.py | 3 +- .../tests/test_asyncio_to_thread.py | 3 +- .../tests/test_asyncio_utils.py | 13 +-- .../tests/test_asyncio_wait.py | 1 + tox.ini | 102 +++++++++--------- 13 files changed, 106 insertions(+), 98 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index bf795b7e64..dc2a75d81e 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -103,6 +103,7 @@ def func(): from wrapt import wrap_function_wrapper as _wrap +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio.metrics import ( ASYNCIO_COROUTINE_ACTIVE, ASYNCIO_COROUTINE_CANCELLED, @@ -215,10 +216,10 @@ def _instrument(self, **kwargs): def _uninstrument(self, **kwargs): for method in self.methods_with_coroutine: - self.uninstrument_method_with_coroutine(method) - self.uninstrument_gather() - self.uninstrument_to_thread() - self.uninstrument_taskgroup_create_task() + uninstrument_method_with_coroutine(method) + uninstrument_gather() + uninstrument_to_thread() + uninstrument_taskgroup_create_task() def instrument_method_with_coroutine(self, method_name): """ @@ -245,24 +246,16 @@ def wrap_coro_or_future(method, instance, args, kwargs): _wrap(asyncio, method_name, wrap_coro_or_future) - def uninstrument_method_with_coroutine(self, method_name): - """ - Uninstrument specified asyncio method. - """ - unwrap(asyncio, method_name) - def instrument_gather(self): def wrap_coros_or_futures(method, instance, args, kwargs): if args and len(args) > 0: # Check if it's a coroutine or future and wrap it wrapped_args = tuple(self.trace_item(item) for item in args) return method(*wrapped_args, **kwargs) + return method(*args, **kwargs) _wrap(asyncio, "gather", wrap_coros_or_futures) - def uninstrument_gather(self): - unwrap(asyncio, "gather") - def instrument_to_thread(self): # to_thread was added in Python 3.9 if sys.version_info < (3, 9): @@ -276,15 +269,10 @@ def wrap_to_thread(method, instance, args, kwargs): wrapped_args = (wrapped_first_arg,) + args[1:] return method(*wrapped_args, **kwargs) + return method(*args, **kwargs) _wrap(asyncio, "to_thread", wrap_to_thread) - def uninstrument_to_thread(self): - # to_thread was added in Python 3.9 - if sys.version_info < (3, 9): - return - unwrap(asyncio, "to_thread") - def instrument_taskgroup_create_task(self): # TaskGroup.create_task was added in Python 3.11 if sys.version_info < (3, 11): @@ -296,14 +284,11 @@ def wrap_taskgroup_create_task(method, instance, args, kwargs): wrapped_coro = self.trace_coroutine(coro) wrapped_args = (wrapped_coro,) + args[1:] return method(*wrapped_args, **kwargs) + return method(*args, **kwargs) - _wrap(asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task) - - def uninstrument_taskgroup_create_task(self): - # TaskGroup.create_task was added in Python 3.11 - if sys.version_info < (3, 11): - return - unwrap(asyncio.TaskGroup, "create_task") + _wrap( + asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task # pylint: disable=no-member + ) def trace_to_thread(self, func): """Trace a function.""" @@ -343,7 +328,7 @@ def trace_item(self, coro_or_future): return coro_or_future if asyncio.iscoroutine(coro_or_future): return self.trace_coroutine(coro_or_future) - elif futures.isfuture(coro_or_future): + if futures.isfuture(coro_or_future): return self.trace_future(coro_or_future) return coro_or_future @@ -527,3 +512,28 @@ def create_to_thread_metric(self): description="Number of asyncio function finished", unit="1", ) + + +def uninstrument_taskgroup_create_task(): + # TaskGroup.create_task was added in Python 3.11 + if sys.version_info < (3, 11): + return + unwrap(asyncio.TaskGroup, "create_task") # pylint: disable=no-member + + +def uninstrument_to_thread(): + # to_thread was added in Python 3.9 + if sys.version_info < (3, 9): + return + unwrap(asyncio, "to_thread") + + +def uninstrument_gather(): + unwrap(asyncio, "gather") + + +def uninstrument_method_with_coroutine(method_name): + """ + Uninstrument specified asyncio method. + """ + unwrap(asyncio, method_name) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index 78d700fdff..c196a7bda7 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -13,6 +13,7 @@ # limitations under the License. import os +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index ae887af44d..b812426685 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -14,6 +14,7 @@ import asyncio from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import ( ASYNCIO_COROUTINE_ACTIVE, ASYNCIO_COROUTINE_CANCELLED, diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py index af62919156..38962c6b1e 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -14,6 +14,7 @@ import asyncio from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, @@ -46,8 +47,6 @@ async def async_func(): asyncio.run(async_func()) spans = self.memory_exporter.get_finished_spans() - """ - OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep" - """ + self.assertEqual(len(spans), 1) self.assertEqual(spans[0].name, "asyncio.coro-sleep") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index f0d89aa00c..a160c23850 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -16,6 +16,7 @@ import pytest +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import ( ASYNCIO_FUTURES_ACTIVE, ASYNCIO_FUTURES_CANCELLED, @@ -92,7 +93,7 @@ async def test(): if span.name == "root": self.assertEqual(span.parent, None) if span.name == "asyncio.future": - self.assertNotEquals(span.parent.trace_id, 0) + self.assertNotEqual(span.parent.trace_id, 0) for metric in ( self.memory_metrics_reader.get_metrics_data() @@ -101,7 +102,7 @@ async def test(): .metrics ): if metric.name == ASYNCIO_FUTURES_DURATION: - self.assertEquals(metric.data.data_points[0].count, 1) + self.assertEqual(metric.data.data_points[0].count, 1) elif metric.name == ASYNCIO_FUTURES_ACTIVE: self.assertEqual(metric.data.data_points[0].value, 0) elif metric.name == ASYNCIO_FUTURES_CREATED: diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py index 74909d26e1..6d9533c271 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -14,6 +14,7 @@ import asyncio from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py index 4070a29450..7f4723ec24 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_integration.py @@ -14,6 +14,7 @@ import asyncio from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, @@ -31,9 +32,6 @@ def setUp(self): __name__, ) - def tearDown(self): - super().tearDown() - @patch.dict( "os.environ", {OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE: "sleep"} ) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py index 0de870ec29..fdf4bcb353 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_run_coroutine_threadsafe.py @@ -16,6 +16,7 @@ from concurrent.futures import ThreadPoolExecutor from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py index f775efcdb4..e02f63aa42 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_taskgroup.py @@ -15,6 +15,7 @@ import sys from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, @@ -51,7 +52,7 @@ def test_task_group_create_task(self): return async def main(): - async with asyncio.TaskGroup() as tg: + async with asyncio.TaskGroup() as tg: # pylint: disable=no-member for _ in range(10): tg.create_task(async_func()) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index fe494ebdaa..8f2538af21 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -15,6 +15,7 @@ import sys from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE, @@ -63,7 +64,7 @@ async def to_thread(): .metrics ): if metric.name == "asyncio.to_thread.duration": - self.assertEquals(metric.data.data_points[0].count, 1) + self.assertEqual(metric.data.data_points[0].count, 1) elif metric.name == "asyncio.to_thread.active": self.assertEqual(metric.data.data_points[0].value, 0) elif metric.name == "asyncio.to_thread.created": diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py index 5e5efb0522..f3974e2d43 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_utils.py @@ -14,10 +14,15 @@ from unittest import TestCase from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, ) +from opentelemetry.instrumentation.asyncio.utils import ( + get_coros_to_trace, + get_future_trace_enabled, +) class TestAsyncioToThread(TestCase): @@ -28,10 +33,6 @@ class TestAsyncioToThread(TestCase): }, ) def test_separator(self): - from opentelemetry.instrumentation.asyncio.utils import ( - get_coros_to_trace, - ) - self.assertEqual( get_coros_to_trace(), {"test1", "test2", "test3", "test4"} ) @@ -40,8 +41,4 @@ def test_separator(self): "os.environ", {OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED: "true"} ) def test_future_trace_enabled(self): - from opentelemetry.instrumentation.asyncio.utils import ( - get_future_trace_enabled, - ) - self.assertEqual(get_future_trace_enabled(), True) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py index f00c81310b..77064aeafa 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_wait.py @@ -15,6 +15,7 @@ import sys from unittest.mock import patch +# pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, diff --git a/tox.ini b/tox.ini index 1355d4c69a..d4b8bd4931 100644 --- a/tox.ini +++ b/tox.ini @@ -534,60 +534,56 @@ commands_pre = python -m pip install "{env:CORE_REPO}#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils" python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test] python -m pip install -e {toxinidir}/opentelemetry-instrumentation[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] - ; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] - # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install - # for your OS to install the required dependencies - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] - python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] +; ; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] +; # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install +; # for your OS to install the required dependencies +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] +; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] - python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] - # requires snappy headers to be available on the system - python -m pip install -e {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] - python -m pip install -e {toxinidir}/resource/opentelemetry-resource-detector-container[test] - python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-aws-xray[test] - python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-ot-trace[test] +; python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] + python -m pip install -e {toxinidir}/opentelemetry-distro[test] commands = From 36032901fd0d72aabdffc95a6888bea20617333e Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 22:53:34 +0900 Subject: [PATCH 31/50] modified lint results --- tox.ini | 102 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/tox.ini b/tox.ini index d4b8bd4931..1355d4c69a 100644 --- a/tox.ini +++ b/tox.ini @@ -534,56 +534,60 @@ commands_pre = python -m pip install "{env:CORE_REPO}#egg=opentelemetry-test-utils&subdirectory=tests/opentelemetry-test-utils" python -m pip install -e {toxinidir}/util/opentelemetry-util-http[test] python -m pip install -e {toxinidir}/opentelemetry-instrumentation[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] -; ; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] -; # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install -; # for your OS to install the required dependencies -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] -; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-botocore[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto3sqs[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-django[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-falcon[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-boto[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-flask[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-cassandra[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-celery[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pika[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aio-pika[test] + ; python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sklearn[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-fastapi[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-jinja2[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-kafka-python[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-confluent-kafka[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-logging[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymemcache[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-psycopg2[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-client[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiohttp-server[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlite3[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pyramid[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-urllib3[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymysql[test] + # prerequisite: follow the instructions here https://github.com/PyMySQL/mysqlclient#install + # for your OS to install the required dependencies + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysqlclient[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-pymongo[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-elasticsearch[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncpg[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tornado[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-tortoiseorm[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-mysql[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-httpx[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aws-lambda[test] + python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics[test] python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asyncio[test] -; python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] - + python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-richconsole[test] + # requires snappy headers to be available on the system + python -m pip install -e {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws[test] + python -m pip install -e {toxinidir}/resource/opentelemetry-resource-detector-container[test] + python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-aws-xray[test] + python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-ot-trace[test] python -m pip install -e {toxinidir}/opentelemetry-distro[test] commands = From 7cc46182562b403102ad16420da04f5343b74260 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 23:04:53 +0900 Subject: [PATCH 32/50] modified lint results --- .../src/opentelemetry/instrumentation/asyncio/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index dc2a75d81e..e34133ffbc 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -287,7 +287,9 @@ def wrap_taskgroup_create_task(method, instance, args, kwargs): return method(*args, **kwargs) _wrap( - asyncio.TaskGroup, "create_task", wrap_taskgroup_create_task # pylint: disable=no-member + asyncio.TaskGroup, # pylint: disable=no-member + "create_task", + wrap_taskgroup_create_task, ) def trace_to_thread(self, func): From 1f0f340e7d2c02df0f8968d4c2a51c30aafe9a0f Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 23:14:26 +0900 Subject: [PATCH 33/50] modified lint results --- .../opentelemetry-instrumentation-asyncio/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index ee5a28bf47..e23b2412fc 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -1,5 +1,5 @@ OpenTelemetry asyncio Instrumentation -=========================== +====================================== |pypi| @@ -19,7 +19,7 @@ Set the name of the coroutine you want to trace. export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ---------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------ .. code:: export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 From b036ba30b207c79c06d0661ff139bc370443dd5f Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Sat, 23 Dec 2023 23:29:40 +0900 Subject: [PATCH 34/50] modified lint results --- .../opentelemetry-instrumentation-asyncio/README.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index e23b2412fc..1a94a0c223 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -15,17 +15,20 @@ The metric for coroutine, future, is generated even if there is no setting to ge Set the name of the coroutine you want to trace. ------------------------------------------------- -.. code:: +.. code:: bash + export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. ------------------------------------------------------------------------------------------------------------------------ -.. code:: +.. code:: bash + export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 For future, set it up like this ----------------------------------------------- -.. code:: +.. code:: bash + export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true Run instrumented application @@ -122,6 +125,6 @@ Installation References ---------- -* `OpenTelemetry asyncio/ Tracing /.html>`_ +* `OpenTelemetry asyncio/ Tracing `_ * `OpenTelemetry Project `_ * `OpenTelemetry Python Examples `_ From a8d5e165c0b1c97d217a20ad6cb4025988eea9b8 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Wed, 3 Jan 2024 23:21:04 +0900 Subject: [PATCH 35/50] include feedback --- .../README.rst | 26 +- .../instrumentation/asyncio/__init__.py | 261 ++++-------------- .../instrumentation/asyncio/metrics.py | 62 ----- .../tests/test_asyncio_cancellation.py | 36 +-- .../tests/test_asyncio_ensure_future.py | 42 +-- 5 files changed, 78 insertions(+), 349 deletions(-) delete mode 100644 instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 1a94a0c223..c11e343ac3 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -9,7 +9,7 @@ OpenTelemetry asyncio Instrumentation AsyncioInstrumentor: Tracing Requests Made by the Asyncio Library -The opentelemetry-instrumentation-asycnio package allows tracing asyncio applications. +The opentelemetry-instrumentation-asyncio package allows tracing asyncio applications. The metric for coroutine, future, is generated even if there is no setting to generate a span. @@ -85,28 +85,8 @@ Run instrumented application asyncio metric types ---------------------- -* `asyncio.futures.duration` (ms) - Duration of the future -* `asyncio.futures.exceptions` (count) - Number of exceptions raised by the future -* `asyncio.futures.cancelled` (count) - Number of futures cancelled -* `asyncio.futures.created` (count) - Number of futures created -* `asyncio.futures.active` (count) - Number of futures active -* `asyncio.futures.finished` (count) - Number of futures finished -* `asyncio.futures.timeouts` (count) - Number of futures timed out - -* `asyncio.coroutine.duration` (ms) - Duration of the coroutine -* `asyncio.coroutine.exceptions` (count) - Number of exceptions raised by the coroutine -* `asyncio.coroutine.created` (count) - Number of coroutines created -* `asyncio.coroutine.active` (count) - Number of coroutines active -* `asyncio.coroutine.finished` (count) - Number of coroutines finished -* `asyncio.coroutine.timeouts` (count) - Number of coroutines timed out -* `asyncio.coroutine.cancelled` (count) - Number of coroutines cancelled - -* `asyncio.to_thread.duration` (ms) - Duration of the to_thread -* `asyncio.to_thread.exceptions` (count) - Number of exceptions raised by the to_thread -* `asyncio.to_thread.created` (count) - Number of to_thread created -* `asyncio.to_thread.active` (count) - Number of to_thread active -* `asyncio.to_thread.finished` (count) - Number of to_thread finished - +* `asyncio.process.duration` (seconds) - Duration of asyncio process +* `asyncio.process.count` (count) - Number of asyncio process API diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index e34133ffbc..bee967b770 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -69,27 +69,8 @@ def func(): asyncio metric types --------------------- -* asyncio.futures.duration (ms) - Duration of the future -* asyncio.futures.exceptions (count) - Number of exceptions raised by the future -* asyncio.futures.cancelled (count) - Number of futures cancelled -* asyncio.futures.created (count) - Number of futures created -* asyncio.futures.active (count) - Number of futures active -* asyncio.futures.finished (count) - Number of futures finished -* asyncio.futures.timeouts (count) - Number of futures timed out - -* asyncio.coroutine.duration (ms) - Duration of the coroutine -* asyncio.coroutine.exceptions (count) - Number of exceptions raised by the coroutine -* asyncio.coroutine.created (count) - Number of coroutines created -* asyncio.coroutine.active (count) - Number of coroutines active -* asyncio.coroutine.finished (count) - Number of coroutines finished -* asyncio.coroutine.timeouts (count) - Number of coroutines timed out -* asyncio.coroutine.cancelled (count) - Number of coroutines cancelled - -* asyncio.to_thread.duration (ms) - Duration of the to_thread -* asyncio.to_thread.exceptions (count) - Number of exceptions raised by the to_thread -* asyncio.to_thread.created (count) - Number of to_thread created -* asyncio.to_thread.active (count) - Number of to_thread active -* asyncio.to_thread.finished (count) - Number of to_thread finished +* asyncio.process.duration (seconds) - Duration of asyncio process +* asyncio.process.count (count) - Number of asyncio process API @@ -103,30 +84,6 @@ def func(): from wrapt import wrap_function_wrapper as _wrap -# pylint: disable=no-name-in-module -from opentelemetry.instrumentation.asyncio.metrics import ( - ASYNCIO_COROUTINE_ACTIVE, - ASYNCIO_COROUTINE_CANCELLED, - ASYNCIO_COROUTINE_CREATED, - ASYNCIO_COROUTINE_DURATION, - ASYNCIO_COROUTINE_EXCEPTIONS, - ASYNCIO_COROUTINE_FINISHED, - ASYNCIO_COROUTINE_NAME, - ASYNCIO_COROUTINE_TIMEOUTS, - ASYNCIO_EXCEPTIONS_NAME, - ASYNCIO_FUTURES_ACTIVE, - ASYNCIO_FUTURES_CANCELLED, - ASYNCIO_FUTURES_CREATED, - ASYNCIO_FUTURES_DURATION, - ASYNCIO_FUTURES_EXCEPTIONS, - ASYNCIO_FUTURES_FINISHED, - ASYNCIO_FUTURES_TIMEOUTS, - ASYNCIO_TO_THREAD_ACTIVE, - ASYNCIO_TO_THREAD_CREATED, - ASYNCIO_TO_THREAD_DURATION, - ASYNCIO_TO_THREAD_EXCEPTIONS, - ASYNCIO_TO_THREAD_FINISHED, -) from opentelemetry.instrumentation.asyncio.package import _instruments from opentelemetry.instrumentation.asyncio.utils import ( get_coros_to_trace, @@ -161,27 +118,8 @@ class AsyncioInstrumentor(BaseInstrumentor): def __init__(self): super().__init__() - self.to_thread_duration_metric = None - self.to_thread_exception_metric = None - self.to_thread_active_metric = None - self.to_thread_created_metric = None - self.to_thread_finished_metric = None - - self.coro_duration_metric = None - self.coro_exception_metric = None - self.coro_cancelled_metric = None - self.coro_active_metric = None - self.coro_created_metric = None - self.coro_finished_metric = None - self.coro_timeout_metric = None - - self.future_duration_metric = None - self.future_exception_metric = None - self.future_cancelled_metric = None - self.future_active_metric = None - self.future_created_metric = None - self.future_finished_metric = None - self.future_timeout_metric = None + self.process_duration_metric = None + self.process_counts_metric = None self._tracer = None self._meter = None @@ -203,9 +141,16 @@ def _instrument(self, **kwargs): self._future_active_enabled = get_future_trace_enabled() self._to_thread_name_to_trace = get_to_thread_to_trace() - self.create_coro_metric() - self.create_future_metric() - self.create_to_thread_metric() + self.process_duration_metric = self._meter.create_histogram( + name="asyncio.process.duration", + description="Duration of asyncio process", + unit="seconds", + ) + self.process_counts_metric = self._meter.create_up_down_counter( + name="asyncio.process.count", + description="Number of asyncio process", + unit="1", + ) for method in self.methods_with_coroutine: self.instrument_method_with_coroutine(method) @@ -295,8 +240,6 @@ def wrap_taskgroup_create_task(method, instance, args, kwargs): def trace_to_thread(self, func): """Trace a function.""" start = default_timer() - self.to_thread_created_metric.add(1) - self.to_thread_active_metric.add(1) span = ( self._tracer.start_span( f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__ @@ -304,19 +247,19 @@ def trace_to_thread(self, func): if func.__name__ in self._to_thread_name_to_trace else None ) + attr = {"type": "to_thread", "name": func.__name__} + duration_attr = attr.copy() exception = None try: + attr["state"] = "finished" return func - except Exception as exc: - exception_attr = {ASYNCIO_EXCEPTIONS_NAME: exc.__class__.__name__} - exception = exc - self.to_thread_exception_metric.add(1, exception_attr) + except Exception: + attr["state"] = "exception" raise finally: duration = max(round((default_timer() - start) * 1000), 0) - self.to_thread_duration_metric.record(duration) - self.to_thread_finished_metric.add(1) - self.to_thread_active_metric.add(-1) + self.process_duration_metric.record(duration, duration_attr) + self.process_counts_metric.add(1, attr) if span: if span.is_recording() and exception: span.set_status(Status(StatusCode.ERROR)) @@ -336,42 +279,34 @@ def trace_item(self, coro_or_future): async def trace_coroutine(self, coro): start = default_timer() - coro_attr = { - ASYNCIO_COROUTINE_NAME: coro.__name__, + attr = { + "type": "coroutine", + "name": coro.__name__, } - self.coro_created_metric.add(1, coro_attr) - self.coro_active_metric.add(1, coro_attr) - + duration_attr = attr.copy() span = ( self._tracer.start_span(f"{ASYNCIO_PREFIX}coro-" + coro.__name__) if coro.__name__ in self._coros_name_to_trace else None ) - exception = None try: + attr["state"] = "finished" return await coro # CancelledError is raised when a coroutine is cancelled # before it has a chance to run. We don't want to record # this as an error. except asyncio.CancelledError: - self.coro_cancelled_metric.add(1, coro_attr) - except asyncio.TimeoutError: - self.coro_timeout_metric.add(1, coro_attr) - raise + attr["state"] = "cancelled" except Exception as exc: exception = exc - coro_exception_attr = coro_attr.copy() - coro_exception_attr[ - ASYNCIO_EXCEPTIONS_NAME - ] = exc.__class__.__name__ - self.coro_exception_metric.add(1, coro_exception_attr) + state = determine_state(exception) + attr["state"] = state raise finally: - duration = max(round((default_timer() - start) * 1000), 0) - self.coro_duration_metric.record(duration, coro_attr) - self.coro_finished_metric.add(1, coro_attr) - self.coro_active_metric.add(-1, coro_attr) + duration = max(round(default_timer() - start), 0) + self.process_duration_metric.record(duration, duration_attr) + self.process_counts_metric.add(1, attr) if span: if span.is_recording() and exception: @@ -381,8 +316,6 @@ async def trace_coroutine(self, coro): def trace_future(self, future): start = default_timer() - self.future_created_metric.add(1) - self.future_active_metric.add(1) span = ( self._tracer.start_span(f"{ASYNCIO_PREFIX}future") if self._future_active_enabled @@ -390,21 +323,16 @@ def trace_future(self, future): ) def callback(f): + duration = max(round(default_timer() - start), 0) exception = f.exception() - if isinstance(exception, asyncio.CancelledError): - self.future_cancelled_metric.add(1) - elif isinstance(exception, asyncio.TimeoutError): - self.future_timeout_metric.add(1) - elif exception: - exception_attr = { - ASYNCIO_EXCEPTIONS_NAME: exception.__class__.__name__ - } - self.future_exception_metric.add(1, exception_attr) - - duration = max(round((default_timer() - start) * 1000), 0) - self.future_duration_metric.record(duration) - self.future_finished_metric.add(1) - self.future_active_metric.add(-1) + attr = { + "type": "future", + } + duration_attr = attr.copy() + state = determine_state(exception) + attr["state"] = state + self.process_counts_metric.add(1, attr) + self.process_duration_metric.record(duration, duration_attr) if span: if span.is_recording() and exception: span.set_status(Status(StatusCode.ERROR)) @@ -414,106 +342,15 @@ def callback(f): future.add_done_callback(callback) return future - def create_coro_metric(self): - self.coro_duration_metric = self._meter.create_histogram( - name=ASYNCIO_COROUTINE_DURATION, - description="Duration of asyncio coroutine", - unit="ms", - ) - self.coro_exception_metric = self._meter.create_counter( - name=ASYNCIO_COROUTINE_EXCEPTIONS, - description="Number of exceptions in asyncio coroutine", - unit="1", - ) - self.coro_cancelled_metric = self._meter.create_counter( - name=ASYNCIO_COROUTINE_CANCELLED, - description="Number of asyncio coroutine cancelled", - unit="1", - ) - self.coro_active_metric = self._meter.create_up_down_counter( - name=ASYNCIO_COROUTINE_ACTIVE, - description="Number of asyncio coroutine active", - unit="1", - ) - self.coro_created_metric = self._meter.create_counter( - name=ASYNCIO_COROUTINE_CREATED, - description="Number of asyncio coroutine created", - unit="1", - ) - self.coro_finished_metric = self._meter.create_counter( - name=ASYNCIO_COROUTINE_FINISHED, - description="Number of asyncio coroutine finished", - unit="1", - ) - self.coro_timeout_metric = self._meter.create_counter( - name=ASYNCIO_COROUTINE_TIMEOUTS, - description="Number of asyncio coroutine timeouts", - unit="1", - ) - - def create_future_metric(self): - self.future_duration_metric = self._meter.create_histogram( - name=ASYNCIO_FUTURES_DURATION, - description="Duration of asyncio future", - unit="ms", - ) - self.future_exception_metric = self._meter.create_counter( - name=ASYNCIO_FUTURES_EXCEPTIONS, - description="Number of exceptions in asyncio future", - unit="1", - ) - self.future_cancelled_metric = self._meter.create_counter( - name=ASYNCIO_FUTURES_CANCELLED, - description="Number of asyncio future cancelled", - unit="1", - ) - self.future_created_metric = self._meter.create_counter( - name=ASYNCIO_FUTURES_CREATED, - description="Number of asyncio future created", - unit="1", - ) - self.future_active_metric = self._meter.create_up_down_counter( - name=ASYNCIO_FUTURES_ACTIVE, - description="Number of asyncio future active", - unit="1", - ) - self.future_finished_metric = self._meter.create_counter( - name=ASYNCIO_FUTURES_FINISHED, - description="Number of asyncio future finished", - unit="1", - ) - self.future_timeout_metric = self._meter.create_counter( - name=ASYNCIO_FUTURES_TIMEOUTS, - description="Number of asyncio future timeouts", - unit="1", - ) - def create_to_thread_metric(self): - self.to_thread_duration_metric = self._meter.create_histogram( - name=ASYNCIO_TO_THREAD_DURATION, - description="Duration of asyncio function", - unit="ms", - ) - self.to_thread_exception_metric = self._meter.create_counter( - name=ASYNCIO_TO_THREAD_EXCEPTIONS, - description="Number of exceptions in asyncio function", - unit="1", - ) - self.to_thread_created_metric = self._meter.create_counter( - name=ASYNCIO_TO_THREAD_CREATED, - description="Number of asyncio function created", - unit="1", - ) - self.to_thread_active_metric = self._meter.create_up_down_counter( - name=ASYNCIO_TO_THREAD_ACTIVE, - description="Number of asyncio function active", - unit="1", - ) - self.to_thread_finished_metric = self._meter.create_counter( - name=ASYNCIO_TO_THREAD_FINISHED, - description="Number of asyncio function finished", - unit="1", - ) +def determine_state(exception): + if isinstance(exception, asyncio.CancelledError): + return "cancelled" + if isinstance(exception, asyncio.TimeoutError): + return "timeout" + if exception: + return "exception" + return "finished" def uninstrument_taskgroup_create_task(): diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py deleted file mode 100644 index 92f02b8788..0000000000 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/metrics.py +++ /dev/null @@ -1,62 +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. - -ASYNCIO_COROUTINE_DURATION = "asyncio.coroutine.duration" -ASYNCIO_COROUTINE_EXCEPTIONS = "asyncio.coroutine.exceptions" -ASYNCIO_COROUTINE_CANCELLED = "asyncio.coroutine.cancelled" -ASYNCIO_COROUTINE_ACTIVE = "asyncio.coroutine.active" -ASYNCIO_COROUTINE_CREATED = "asyncio.coroutine.created" -ASYNCIO_COROUTINE_FINISHED = "asyncio.coroutine.finished" -ASYNCIO_COROUTINE_TIMEOUTS = "asyncio.coroutine.timeouts" - -ASYNCIO_COROUTINE_NAME = "coroutine.name" -ASYNCIO_EXCEPTIONS_NAME = "exceptions.name" - -ASYNCIO_FUTURES_DURATION = "asyncio.futures.duration" -ASYNCIO_FUTURES_EXCEPTIONS = "asyncio.futures.exceptions" -ASYNCIO_FUTURES_CANCELLED = "asyncio.futures.cancelled" -ASYNCIO_FUTURES_CREATED = "asyncio.futures.created" -ASYNCIO_FUTURES_ACTIVE = "asyncio.futures.active" -ASYNCIO_FUTURES_FINISHED = "asyncio.futures.finished" -ASYNCIO_FUTURES_TIMEOUTS = "asyncio.futures.timeouts" - -ASYNCIO_TO_THREAD_DURATION = "asyncio.to_thread.duration" -ASYNCIO_TO_THREAD_EXCEPTIONS = "asyncio.to_thread.exceptions" -ASYNCIO_TO_THREAD_CREATED = "asyncio.to_thread.created" -ASYNCIO_TO_THREAD_ACTIVE = "asyncio.to_thread.active" -ASYNCIO_TO_THREAD_FINISHED = "asyncio.to_thread.finished" - -__all__ = [ - "ASYNCIO_COROUTINE_DURATION", - "ASYNCIO_COROUTINE_EXCEPTIONS", - "ASYNCIO_COROUTINE_CANCELLED", - "ASYNCIO_COROUTINE_ACTIVE", - "ASYNCIO_COROUTINE_CREATED", - "ASYNCIO_COROUTINE_FINISHED", - "ASYNCIO_COROUTINE_TIMEOUTS", - "ASYNCIO_COROUTINE_NAME", - "ASYNCIO_EXCEPTIONS_NAME", - "ASYNCIO_FUTURES_DURATION", - "ASYNCIO_FUTURES_EXCEPTIONS", - "ASYNCIO_FUTURES_CANCELLED", - "ASYNCIO_FUTURES_CREATED", - "ASYNCIO_FUTURES_ACTIVE", - "ASYNCIO_FUTURES_FINISHED", - "ASYNCIO_FUTURES_TIMEOUTS", - "ASYNCIO_TO_THREAD_DURATION", - "ASYNCIO_TO_THREAD_EXCEPTIONS", - "ASYNCIO_TO_THREAD_CREATED", - "ASYNCIO_TO_THREAD_ACTIVE", - "ASYNCIO_TO_THREAD_FINISHED", -] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index b812426685..32fc1caffa 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -15,14 +15,7 @@ from unittest.mock import patch # pylint: disable=no-name-in-module -from opentelemetry.instrumentation.asyncio import ( - ASYNCIO_COROUTINE_ACTIVE, - ASYNCIO_COROUTINE_CANCELLED, - ASYNCIO_COROUTINE_CREATED, - ASYNCIO_COROUTINE_DURATION, - ASYNCIO_COROUTINE_FINISHED, - AsyncioInstrumentor, -) +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE, ) @@ -66,13 +59,20 @@ def test_cancel(self): .scope_metrics[0] .metrics ): - if metric.name == ASYNCIO_COROUTINE_CANCELLED: - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == ASYNCIO_COROUTINE_DURATION: - self.assertEqual(metric.data.data_points[0].min != 0, True) - elif metric.name == ASYNCIO_COROUTINE_ACTIVE: - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == ASYNCIO_COROUTINE_CREATED: - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == ASYNCIO_COROUTINE_FINISHED: - self.assertEqual(metric.data.data_points[0].value, 1) + if metric.name == "asyncio.process.duration": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "coroutine") + self.assertIn( + point.attributes["name"], + ["cancellation_coro", "cancellable_coroutine"], + ) + if metric.name == "asyncio.process.count": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "coroutine") + self.assertIn( + point.attributes["name"], + ["cancellation_coro", "cancellable_coroutine"], + ) + self.assertIn( + point.attributes["state"], ["finished", "cancelled"] + ) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index a160c23850..daf3bc55f4 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -17,16 +17,7 @@ import pytest # pylint: disable=no-name-in-module -from opentelemetry.instrumentation.asyncio import ( - ASYNCIO_FUTURES_ACTIVE, - ASYNCIO_FUTURES_CANCELLED, - ASYNCIO_FUTURES_CREATED, - ASYNCIO_FUTURES_DURATION, - ASYNCIO_FUTURES_EXCEPTIONS, - ASYNCIO_FUTURES_FINISHED, - ASYNCIO_FUTURES_TIMEOUTS, - AsyncioInstrumentor, -) +from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor from opentelemetry.instrumentation.asyncio.environment_variables import ( OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED, ) @@ -35,16 +26,6 @@ from .common_test_func import async_func -_expected_metric_names = [ - ASYNCIO_FUTURES_DURATION, - ASYNCIO_FUTURES_EXCEPTIONS, - ASYNCIO_FUTURES_CANCELLED, - ASYNCIO_FUTURES_CREATED, - ASYNCIO_FUTURES_ACTIVE, - ASYNCIO_FUTURES_FINISHED, - ASYNCIO_FUTURES_TIMEOUTS, -] - class TestAsyncioEnsureFuture(TestBase): @patch.dict( @@ -101,17 +82,10 @@ async def test(): .scope_metrics[0] .metrics ): - if metric.name == ASYNCIO_FUTURES_DURATION: - self.assertEqual(metric.data.data_points[0].count, 1) - elif metric.name == ASYNCIO_FUTURES_ACTIVE: - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == ASYNCIO_FUTURES_CREATED: - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == ASYNCIO_FUTURES_FINISHED: - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == ASYNCIO_FUTURES_EXCEPTIONS: - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == ASYNCIO_FUTURES_CANCELLED: - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == ASYNCIO_FUTURES_TIMEOUTS: - self.assertEqual(metric.data.data_points[0].value, 0) + if metric.name == "asyncio.process.duration": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "future") + if metric.name == "asyncio.process.count": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "future") + self.assertEqual(point.attributes["state"], "finished") From 936dc37e59eb4b7e96a7a626a098fbd223209658 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Thu, 4 Jan 2024 09:43:39 +0900 Subject: [PATCH 36/50] include feedback --- .../instrumentation/asyncio/__init__.py | 97 +++++++++---------- .../instrumentation/asyncio/utils.py | 2 +- .../tests/common_test_func.py | 2 +- .../tests/test_asyncio_cancellation.py | 4 +- .../tests/test_asyncio_create_task.py | 2 +- .../tests/test_asyncio_gather.py | 6 +- .../tests/test_asyncio_to_thread.py | 26 ++--- 7 files changed, 64 insertions(+), 75 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index bee967b770..d80ea28076 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -97,7 +97,7 @@ def func(): from opentelemetry.trace import get_tracer from opentelemetry.trace.status import Status, StatusCode -ASYNCIO_PREFIX = "asyncio." +ASYNCIO_PREFIX = "asyncio" class AsyncioInstrumentor(BaseInstrumentor): @@ -118,8 +118,8 @@ class AsyncioInstrumentor(BaseInstrumentor): def __init__(self): super().__init__() - self.process_duration_metric = None - self.process_counts_metric = None + self.process_duration_histogram = None + self.process_counts_counter = None self._tracer = None self._meter = None @@ -131,8 +131,9 @@ def instrumentation_dependencies(self) -> Collection[str]: return _instruments def _instrument(self, **kwargs): - tracer_provider = kwargs.get("tracer_provider") - self._tracer = get_tracer(__name__, __version__, tracer_provider) + self._tracer = get_tracer( + __name__, __version__, kwargs.get("tracer_provider") + ) self._meter = get_meter( __name__, __version__, kwargs.get("meter_provider") ) @@ -141,12 +142,12 @@ def _instrument(self, **kwargs): self._future_active_enabled = get_future_trace_enabled() self._to_thread_name_to_trace = get_to_thread_to_trace() - self.process_duration_metric = self._meter.create_histogram( + self.process_duration_histogram = self._meter.create_histogram( name="asyncio.process.duration", description="Duration of asyncio process", unit="seconds", ) - self.process_counts_metric = self._meter.create_up_down_counter( + self.process_counts_counter = self._meter.create_counter( name="asyncio.process.count", description="Number of asyncio process", unit="1", @@ -166,7 +167,7 @@ def _uninstrument(self, **kwargs): uninstrument_to_thread() uninstrument_taskgroup_create_task() - def instrument_method_with_coroutine(self, method_name): + def instrument_method_with_coroutine(self, method_name: str): """ Instruments specified asyncio method. """ @@ -201,12 +202,12 @@ def wrap_coros_or_futures(method, instance, args, kwargs): _wrap(asyncio, "gather", wrap_coros_or_futures) - def instrument_to_thread(self): + def instrument_to_thread(self) -> None: # to_thread was added in Python 3.9 if sys.version_info < (3, 9): return - def wrap_to_thread(method, instance, args, kwargs): + def wrap_to_thread(method, instance, args, kwargs) -> None: if args: first_arg = args[0] # Wrap the first argument @@ -218,12 +219,12 @@ def wrap_to_thread(method, instance, args, kwargs): _wrap(asyncio, "to_thread", wrap_to_thread) - def instrument_taskgroup_create_task(self): + def instrument_taskgroup_create_task(self) -> None: # TaskGroup.create_task was added in Python 3.11 if sys.version_info < (3, 11): return - def wrap_taskgroup_create_task(method, instance, args, kwargs): + def wrap_taskgroup_create_task(method, instance, args, kwargs) -> None: if args: coro = args[0] wrapped_coro = self.trace_coroutine(coro) @@ -237,18 +238,17 @@ def wrap_taskgroup_create_task(method, instance, args, kwargs): wrap_taskgroup_create_task, ) - def trace_to_thread(self, func): + def trace_to_thread(self, func: callable): """Trace a function.""" start = default_timer() span = ( self._tracer.start_span( - f"{ASYNCIO_PREFIX}to_thread_func-" + func.__name__ + f"{ASYNCIO_PREFIX} to_thread-" + func.__name__ ) if func.__name__ in self._to_thread_name_to_trace else None ) attr = {"type": "to_thread", "name": func.__name__} - duration_attr = attr.copy() exception = None try: attr["state"] = "finished" @@ -257,14 +257,7 @@ def trace_to_thread(self, func): attr["state"] = "exception" raise finally: - duration = max(round((default_timer() - start) * 1000), 0) - self.process_duration_metric.record(duration, duration_attr) - self.process_counts_metric.add(1, attr) - if span: - if span.is_recording() and exception: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(exception) - span.end() + self.record_process(start, attr, span, exception) def trace_item(self, coro_or_future): """Trace a coroutine or future item.""" @@ -283,9 +276,8 @@ async def trace_coroutine(self, coro): "type": "coroutine", "name": coro.__name__, } - duration_attr = attr.copy() span = ( - self._tracer.start_span(f"{ASYNCIO_PREFIX}coro-" + coro.__name__) + self._tracer.start_span(f"{ASYNCIO_PREFIX} coro-" + coro.__name__) if coro.__name__ in self._coros_name_to_trace else None ) @@ -304,46 +296,51 @@ async def trace_coroutine(self, coro): attr["state"] = state raise finally: - duration = max(round(default_timer() - start), 0) - self.process_duration_metric.record(duration, duration_attr) - self.process_counts_metric.add(1, attr) - - if span: - if span.is_recording() and exception: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(exception) - span.end() + self.record_process(start, attr, span, exception) - def trace_future(self, future): + def trace_future(self, future) -> futures.Future: start = default_timer() span = ( - self._tracer.start_span(f"{ASYNCIO_PREFIX}future") + self._tracer.start_span(f"{ASYNCIO_PREFIX} future") if self._future_active_enabled else None ) def callback(f): - duration = max(round(default_timer() - start), 0) exception = f.exception() attr = { "type": "future", } - duration_attr = attr.copy() state = determine_state(exception) attr["state"] = state - self.process_counts_metric.add(1, attr) - self.process_duration_metric.record(duration, duration_attr) - if span: - if span.is_recording() and exception: - span.set_status(Status(StatusCode.ERROR)) - span.record_exception(exception) - span.end() + self.record_process(start, attr, span, exception) future.add_done_callback(callback) return future + def record_process( + self, start: float, attr: dict, span=None, exception=None + ) -> None: + """ + Record the processing time, update histogram and counter, and handle span. + + :param start: Start time of the process. + :param attr: Attributes for the histogram and counter. + :param span: Optional span for tracing. + :param exception: Optional exception occurred during the process. + """ + duration = max(default_timer() - start, 0) + self.process_duration_histogram.record(duration, attr) + self.process_counts_counter.add(1, attr) + + if span: + if span.is_recording() and exception: + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(exception) + span.end() + -def determine_state(exception): +def determine_state(exception: Exception) -> str: if isinstance(exception, asyncio.CancelledError): return "cancelled" if isinstance(exception, asyncio.TimeoutError): @@ -353,25 +350,25 @@ def determine_state(exception): return "finished" -def uninstrument_taskgroup_create_task(): +def uninstrument_taskgroup_create_task() -> None: # TaskGroup.create_task was added in Python 3.11 if sys.version_info < (3, 11): return unwrap(asyncio.TaskGroup, "create_task") # pylint: disable=no-member -def uninstrument_to_thread(): +def uninstrument_to_thread() -> None: # to_thread was added in Python 3.9 if sys.version_info < (3, 9): return unwrap(asyncio, "to_thread") -def uninstrument_gather(): +def uninstrument_gather() -> None: unwrap(asyncio, "gather") -def uninstrument_method_with_coroutine(method_name): +def uninstrument_method_with_coroutine(method_name: str) -> None: """ Uninstrument specified asyncio method. """ diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index c196a7bda7..f95281949c 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -21,7 +21,7 @@ ) -def separate_coro_names_by_comma(coro_names) -> set: +def separate_coro_names_by_comma(coro_names: str) -> set: """ Function to separate the coroutines to be traced by comma """ diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py index ed8803a1f0..5d06641bc0 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/common_test_func.py @@ -19,7 +19,7 @@ async def async_func(): await asyncio.sleep(0.1) -async def factorial(number): +async def factorial(number: int): factorial_value = 1 for value in range(2, number + 1): await asyncio.sleep(0) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index 32fc1caffa..62905e3eee 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -51,8 +51,8 @@ def test_cancel(self): self.assertEqual(spans[0].context.trace_id, spans[1].context.trace_id) self.assertEqual(spans[2].context.trace_id, spans[1].context.trace_id) - self.assertEqual(spans[0].name, "asyncio.coro-cancellable_coroutine") - self.assertEqual(spans[1].name, "asyncio.coro-cancellation_coro") + self.assertEqual(spans[0].name, "asyncio coro-cancellable_coroutine") + self.assertEqual(spans[1].name, "asyncio coro-cancellation_coro") for metric in ( self.memory_metrics_reader.get_metrics_data() .resource_metrics[0] diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py index 38962c6b1e..9df8d9d14b 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_create_task.py @@ -49,4 +49,4 @@ async def async_func(): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) - self.assertEqual(spans[0].name, "asyncio.coro-sleep") + self.assertEqual(spans[0].name, "asyncio coro-sleep") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py index 6d9533c271..395b46b698 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_gather.py @@ -48,6 +48,6 @@ async def gather_factorial(): asyncio.run(gather_factorial()) spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 3) - self.assertEqual(spans[0].name, "asyncio.coro-factorial") - self.assertEqual(spans[1].name, "asyncio.coro-factorial") - self.assertEqual(spans[2].name, "asyncio.coro-factorial") + self.assertEqual(spans[0].name, "asyncio coro-factorial") + self.assertEqual(spans[1].name, "asyncio coro-factorial") + self.assertEqual(spans[2].name, "asyncio coro-factorial") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index 8f2538af21..54c85374c9 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -56,26 +56,18 @@ async def to_thread(): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) - assert spans[0].name == "asyncio.to_thread_func-multiply" + assert spans[0].name == "asyncio to_thread-multiply" for metric in ( self.memory_metrics_reader.get_metrics_data() .resource_metrics[0] .scope_metrics[0] .metrics ): - if metric.name == "asyncio.to_thread.duration": - self.assertEqual(metric.data.data_points[0].count, 1) - elif metric.name == "asyncio.to_thread.active": - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == "asyncio.to_thread.created": - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == "asyncio.to_thread.finished": - self.assertEqual(metric.data.data_points[0].value, 1) - elif metric.name == "asyncio.to_thread.exceptions": - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == "asyncio.to_thread.cancelled": - self.assertEqual(metric.data.data_points[0].value, 0) - elif metric.name == "asyncio.to_thread.name": - self.assertEqual( - metric.data.data_points[0].value, "multiply" - ) + if metric.name == "asyncio.process.duration": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "to_thread") + self.assertEqual(point.attributes["name"], "multiply") + if metric.name == "asyncio.process.count": + for point in metric.data.data_points: + self.assertEqual(point.attributes["type"], "to_thread") + self.assertEqual(point.attributes["name"], "multiply") From 69c15e862db4b6f9cc181c1733b382e3f0cdb887 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Thu, 4 Jan 2024 09:52:30 +0900 Subject: [PATCH 37/50] include feedback --- .../src/opentelemetry/instrumentation/asyncio/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index d80ea28076..9033bfeffb 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -145,12 +145,12 @@ def _instrument(self, **kwargs): self.process_duration_histogram = self._meter.create_histogram( name="asyncio.process.duration", description="Duration of asyncio process", - unit="seconds", + unit="s", ) self.process_counts_counter = self._meter.create_counter( name="asyncio.process.count", description="Number of asyncio process", - unit="1", + unit="{process}", ) for method in self.methods_with_coroutine: From f8a0b5e9f80606a10f45b1c61310183e984f4d8a Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Thu, 4 Jan 2024 11:22:16 +0900 Subject: [PATCH 38/50] modify docs test results --- .../src/opentelemetry/instrumentation/asyncio/__init__.py | 2 +- .../tests/test_asyncio_ensure_future.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index 9033bfeffb..d3e21fd08d 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -298,7 +298,7 @@ async def trace_coroutine(self, coro): finally: self.record_process(start, attr, span, exception) - def trace_future(self, future) -> futures.Future: + def trace_future(self, future): start = default_timer() span = ( self._tracer.start_span(f"{ASYNCIO_PREFIX} future") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index daf3bc55f4..26de02b77d 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -73,7 +73,7 @@ async def test(): for span in spans: if span.name == "root": self.assertEqual(span.parent, None) - if span.name == "asyncio.future": + if span.name == "asyncio future": self.assertNotEqual(span.parent.trace_id, 0) for metric in ( From 2c6d9441bd73ccae4d9164e43c6054b8941059d0 Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:37:40 +0900 Subject: [PATCH 39/50] Update instrumentation/opentelemetry-instrumentation-asyncio/README.rst Co-authored-by: Aaron Abbott --- .../opentelemetry-instrumentation-asyncio/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index c11e343ac3..ccd793ac3f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -19,7 +19,7 @@ Set the name of the coroutine you want to trace. export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 -If you want to keep track of which function to use in the to_thread function of asyncio, set the name of the function. +If you want to trace specific blocking functions executed with the ``to_thread`` function of asyncio, set the name of the functions in ``OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE``. ------------------------------------------------------------------------------------------------------------------------ .. code:: bash From 214a851926d546a944f0b1838be80592be1cebb9 Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:37:46 +0900 Subject: [PATCH 40/50] Update instrumentation/opentelemetry-instrumentation-asyncio/README.rst Co-authored-by: Aaron Abbott --- .../opentelemetry-instrumentation-asyncio/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index ccd793ac3f..5b609d21ee 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -13,7 +13,7 @@ The opentelemetry-instrumentation-asyncio package allows tracing asyncio applica The metric for coroutine, future, is generated even if there is no setting to generate a span. -Set the name of the coroutine you want to trace. +Set the names of coroutines you want to trace. ------------------------------------------------- .. code:: bash From f11322ac562d3010e9f3252bb3aa98b0c10a9ac5 Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:37:56 +0900 Subject: [PATCH 41/50] Update instrumentation/opentelemetry-instrumentation-asyncio/README.rst Co-authored-by: Aaron Abbott --- .../opentelemetry-instrumentation-asyncio/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 5b609d21ee..2f84ae4618 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -25,7 +25,7 @@ If you want to trace specific blocking functions executed with the ``to_thread`` export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 -For future, set it up like this +You can enable tracing futures with ``OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED`` ----------------------------------------------- .. code:: bash From ef45d62996a3df2c406c2edef15cbf473fbda6ef Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:38:04 +0900 Subject: [PATCH 42/50] Update instrumentation/opentelemetry-instrumentation-asyncio/README.rst Co-authored-by: Aaron Abbott --- .../opentelemetry-instrumentation-asyncio/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 2f84ae4618..144d136ccc 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -10,7 +10,7 @@ AsyncioInstrumentor: Tracing Requests Made by the Asyncio Library The opentelemetry-instrumentation-asyncio package allows tracing asyncio applications. -The metric for coroutine, future, is generated even if there is no setting to generate a span. +It also includes metrics for duration and counts of coroutines and futures. Metrics are generated even if coroutines are not traced. Set the names of coroutines you want to trace. From e93aa9b9d7523e36293f3e92ea5dc2f6e6294054 Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:38:23 +0900 Subject: [PATCH 43/50] Update instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py Co-authored-by: Aaron Abbott --- .../src/opentelemetry/instrumentation/asyncio/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index f95281949c..ac7b429056 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -27,7 +27,7 @@ def separate_coro_names_by_comma(coro_names: str) -> set: """ if coro_names is None: return set() - return set(coro_name.strip() for coro_name in coro_names.split(",")) + return {coro_name.strip() for coro_name in coro_names.split(",")} def get_coros_to_trace() -> set: From b9a303d7ea456f8320ce875187b3730a611551d6 Mon Sep 17 00:00:00 2001 From: Allen Kim Date: Fri, 5 Jan 2024 08:38:32 +0900 Subject: [PATCH 44/50] Update instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py Co-authored-by: Aaron Abbott --- .../src/opentelemetry/instrumentation/asyncio/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index ac7b429056..eb457fb67a 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -21,7 +21,7 @@ ) -def separate_coro_names_by_comma(coro_names: str) -> set: +def separate_coro_names_by_comma(coro_names: str) -> Set[str]: """ Function to separate the coroutines to be traced by comma """ From 5f7bd4ba1812aa55fdd68f3b39de6e8936878862 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Fri, 5 Jan 2024 09:13:33 +0900 Subject: [PATCH 45/50] include feedback --- .../src/opentelemetry/instrumentation/asyncio/__init__.py | 8 ++++---- .../src/opentelemetry/instrumentation/asyncio/utils.py | 1 + .../tests/test_asyncio_cancellation.py | 2 +- .../tests/test_asyncio_ensure_future.py | 2 +- .../tests/test_asyncio_to_thread.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py index d3e21fd08d..68e3d0839f 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/__init__.py @@ -119,7 +119,7 @@ class AsyncioInstrumentor(BaseInstrumentor): def __init__(self): super().__init__() self.process_duration_histogram = None - self.process_counts_counter = None + self.process_created_counter = None self._tracer = None self._meter = None @@ -147,8 +147,8 @@ def _instrument(self, **kwargs): description="Duration of asyncio process", unit="s", ) - self.process_counts_counter = self._meter.create_counter( - name="asyncio.process.count", + self.process_created_counter = self._meter.create_counter( + name="asyncio.process.created", description="Number of asyncio process", unit="{process}", ) @@ -331,7 +331,7 @@ def record_process( """ duration = max(default_timer() - start, 0) self.process_duration_histogram.record(duration, attr) - self.process_counts_counter.add(1, attr) + self.process_created_counter.add(1, attr) if span: if span.is_recording() and exception: diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py index eb457fb67a..15c78ae1ce 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/src/opentelemetry/instrumentation/asyncio/utils.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import os +from typing import Set # pylint: disable=no-name-in-module from opentelemetry.instrumentation.asyncio.environment_variables import ( diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py index 62905e3eee..9172cd4458 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_cancellation.py @@ -66,7 +66,7 @@ def test_cancel(self): point.attributes["name"], ["cancellation_coro", "cancellable_coroutine"], ) - if metric.name == "asyncio.process.count": + if metric.name == "asyncio.process.created": for point in metric.data.data_points: self.assertEqual(point.attributes["type"], "coroutine") self.assertIn( diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py index 26de02b77d..4907aa4bf8 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_ensure_future.py @@ -85,7 +85,7 @@ async def test(): if metric.name == "asyncio.process.duration": for point in metric.data.data_points: self.assertEqual(point.attributes["type"], "future") - if metric.name == "asyncio.process.count": + if metric.name == "asyncio.process.created": for point in metric.data.data_points: self.assertEqual(point.attributes["type"], "future") self.assertEqual(point.attributes["state"], "finished") diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py index 54c85374c9..b53a6edc08 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py +++ b/instrumentation/opentelemetry-instrumentation-asyncio/tests/test_asyncio_to_thread.py @@ -67,7 +67,7 @@ async def to_thread(): for point in metric.data.data_points: self.assertEqual(point.attributes["type"], "to_thread") self.assertEqual(point.attributes["name"], "multiply") - if metric.name == "asyncio.process.count": + if metric.name == "asyncio.process.created": for point in metric.data.data_points: self.assertEqual(point.attributes["type"], "to_thread") self.assertEqual(point.attributes["name"], "multiply") From b3f460471ff4ee8e04d1fca25ffe85a1de5a8092 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Fri, 5 Jan 2024 09:27:28 +0900 Subject: [PATCH 46/50] include feedback --- .../opentelemetry-instrumentation-asyncio/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst index 144d136ccc..d78e846793 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncio/README.rst @@ -20,13 +20,13 @@ Set the names of coroutines you want to trace. export OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE=coro_name,coro_name2,coro_name3 If you want to trace specific blocking functions executed with the ``to_thread`` function of asyncio, set the name of the functions in ``OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE``. ------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ .. code:: bash export OTEL_PYTHON_ASYNCIO_TO_THREAD_FUNCTION_NAMES_TO_TRACE=func_name,func_name2,func_name3 You can enable tracing futures with ``OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED`` ------------------------------------------------ +----------------------------------------------------------------------------------------------- .. code:: bash export OTEL_PYTHON_ASYNCIO_FUTURE_TRACE_ENABLED=true @@ -103,7 +103,7 @@ Installation References ----------- +----------- * `OpenTelemetry asyncio/ Tracing `_ * `OpenTelemetry Project `_ From eb5e156687228ccb0ffdd23b3094236967951a97 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 6 Feb 2024 08:12:17 +0900 Subject: [PATCH 47/50] drop python 3.7 support --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index c36f5d2edb..b334f08ea0 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -18,7 +18,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", From 9ac37a0f52d1ee62678115729f8f8ccdcd6f6d80 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 6 Feb 2024 08:13:08 +0900 Subject: [PATCH 48/50] drop python 3.7 support --- .../opentelemetry-instrumentation-asyncio/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml index b334f08ea0..0624714d99 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml +++ b/instrumentation/opentelemetry-instrumentation-asyncio/pyproject.toml @@ -8,7 +8,7 @@ dynamic = ["version"] description = "OpenTelemetry instrumentation for asyncio" readme = "README.rst" license = "Apache-2.0" -requires-python = ">=3.7" +requires-python = ">=3.8" authors = [ { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, ] From 9c7529414bdc082b57b7a2707ef8ec3fbed8806e Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 13 Feb 2024 10:55:00 +0900 Subject: [PATCH 49/50] Removed from default_instrumentations --- .../src/opentelemetry/instrumentation/bootstrap_gen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 92ac4d9768..bf94b44d25 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -186,7 +186,6 @@ }, ] default_instrumentations = [ - "opentelemetry-instrumentation-asyncio==0.44b0.dev", "opentelemetry-instrumentation-aws-lambda==0.44b0.dev", "opentelemetry-instrumentation-dbapi==0.44b0.dev", "opentelemetry-instrumentation-logging==0.44b0.dev", From e84ee7cfb2fad6cb79406684e7edf17c43f6d3a7 Mon Sep 17 00:00:00 2001 From: "allen.k1m" Date: Tue, 13 Feb 2024 11:19:54 +0900 Subject: [PATCH 50/50] Recover --- .../src/opentelemetry/instrumentation/bootstrap_gen.py | 1 + tox.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index bf94b44d25..92ac4d9768 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -186,6 +186,7 @@ }, ] default_instrumentations = [ + "opentelemetry-instrumentation-asyncio==0.44b0.dev", "opentelemetry-instrumentation-aws-lambda==0.44b0.dev", "opentelemetry-instrumentation-dbapi==0.44b0.dev", "opentelemetry-instrumentation-logging==0.44b0.dev", diff --git a/tox.ini b/tox.ini index ddc546aa9f..c914ce61c9 100644 --- a/tox.ini +++ b/tox.ini @@ -228,7 +228,7 @@ envlist = py3{8,9,10}-test-instrumentation-confluent-kafka ; opentelemetry-instrumentation-asyncio - py3{7,8,9,10,11}-test-instrumentation-asyncio + py3{8,9,10,11}-test-instrumentation-asyncio ; opentelemetry-instrumentation-cassandra py3{8,9,10,11}-test-instrumentation-cassandra