diff --git a/.github/component_owners.yml b/.github/component_owners.yml index 8292e2f52..44f9ce236 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -1,5 +1,9 @@ components: + instrumentation/opentelemetry-instrumentation-boto3sqs: + - oxeye-nikolay + - nikosokolik + instrumentation/opentelemetry-instrumentation-kafka-python: - nozik @@ -7,9 +11,9 @@ components: - oxeye-nikolay - nikosokolik - instrumentation/opentelemetry-instrumentation-boto3sqs: - - oxeye-nikolay - - nikosokolik + instrumentation/opentelemetry-instrumentation-remoulade: + - ben-natan + - machine424 propagator/opentelemetry-propagator-aws-xray: - NathanielRN diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b9d1705..e4d5c7b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([1109](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1109)) - cleanup type hints for textmap `Getter` and `Setter` classes ([1106](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1106)) + +### Added +- `opentelemetry-instrumentation-remoulade` Initial release + ([#1082](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1082)) ## [1.12.0rc1-0.31b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc1-0.31b0) - 2022-05-17 - - ### Fixed - `opentelemetry-instrumentation-aiohttp-client` make span attributes available to sampler ([1072](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1072)) diff --git a/docs-requirements.txt b/docs-requirements.txt index a681a9b84..0e1bbfc7e 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -33,6 +33,7 @@ pymongo~=3.1 PyMySQL~=0.9.3 pyramid>=1.7 redis>=2.6 +remoulade>=0.50 sqlalchemy>=1.0 tornado>=5.1.1 ddtrace>=0.34.0 diff --git a/instrumentation/README.md b/instrumentation/README.md index e4347f03a..08e25c89c 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -29,6 +29,7 @@ | [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | | [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | | [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | +| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | | [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | | [opentelemetry-instrumentation-sklearn](./opentelemetry-instrumentation-sklearn) | scikit-learn ~= 0.24.0 | | [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy | diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/MANIFEST.in b/instrumentation/opentelemetry-instrumentation-remoulade/MANIFEST.in new file mode 100644 index 000000000..aed3e3327 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/MANIFEST.in @@ -0,0 +1,9 @@ +graft src +graft tests +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include CHANGELOG.md +include MANIFEST.in +include README.rst +include LICENSE diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/README.rst b/instrumentation/opentelemetry-instrumentation-remoulade/README.rst new file mode 100644 index 000000000..46effe07f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/README.rst @@ -0,0 +1,23 @@ +OpenTelemetry Remoulade Instrumentation +======================================= + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-remoulade.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-remoulade/ + +This library allows tracing requests made by the Remoulade library. + +Installation +------------ + +:: + + pip install opentelemetry-instrumentation-remoulade + +References +---------- + +* `OpenTelemetry Remoulade Instrumentation `_ +* `OpenTelemetry Project `_ +* `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg b/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg new file mode 100644 index 000000000..e4fe1fe00 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/setup.cfg @@ -0,0 +1,56 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +[metadata] +name = opentelemetry-instrumentation-remoulade +description = OpenTelemetry Remoulade instrumentation +long_description = file: README.rst +long_description_content_type = text/x-rst +author = OpenTelemetry Authors +author_email = cncf-opentelemetry-contributors@lists.cncf.io +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-remoulade +platforms = any +license = Apache-2.0 +classifiers = + Development Status :: 4 - Beta + Intended Audience :: Developers + License :: OSI Approved :: Apache Software License + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + +[options] +python_requires = >=3.7 +package_dir= + =src +packages=find_namespace: +install_requires = + opentelemetry-api ~= 1.10 + opentelemetry-semantic-conventions == 0.31b0 + opentelemetry-instrumentation == 0.31b0 + +[options.extras_require] +test = + opentelemetry-test-utils == 0.31b0 + opentelemetry-sdk ~= 1.10 + +[options.packages.find] +where = src + +[options.entry_points] +opentelemetry_instrumentor = + remoulade = opentelemetry.instrumentation.remoulade:RemouladeInstrumentor diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/setup.py b/instrumentation/opentelemetry-instrumentation-remoulade/setup.py new file mode 100644 index 000000000..4df9c5a2e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/setup.py @@ -0,0 +1,99 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# DO NOT EDIT. THIS FILE WAS AUTOGENERATED FROM templates/instrumentation_setup.py.txt. +# RUN `python scripts/generate_setup.py` TO REGENERATE. + + +import distutils.cmd +import json +import os +from configparser import ConfigParser + +import setuptools + +config = ConfigParser() +config.read("setup.cfg") + +# We provide extras_require parameter to setuptools.setup later which +# overwrites the extras_require section from setup.cfg. To support extras_require +# section in setup.cfg, we load it here and merge it with the extras_require param. +extras_require = {} +if "options.extras_require" in config: + for key, value in config["options.extras_require"].items(): + extras_require[key] = [v for v in value.split("\n") if v.strip()] + +BASE_DIR = os.path.dirname(__file__) +PACKAGE_INFO = {} + +VERSION_FILENAME = os.path.join( + BASE_DIR, + "src", + "opentelemetry", + "instrumentation", + "remoulade", + "version.py", +) +with open(VERSION_FILENAME, encoding="utf-8") as f: + exec(f.read(), PACKAGE_INFO) + +PACKAGE_FILENAME = os.path.join( + BASE_DIR, + "src", + "opentelemetry", + "instrumentation", + "remoulade", + "package.py", +) +with open(PACKAGE_FILENAME, encoding="utf-8") as f: + exec(f.read(), PACKAGE_INFO) + +# Mark any instruments/runtime dependencies as test dependencies as well. +extras_require["instruments"] = PACKAGE_INFO["_instruments"] +test_deps = extras_require.get("test", []) +for dep in extras_require["instruments"]: + test_deps.append(dep) + +extras_require["test"] = test_deps + + +class JSONMetadataCommand(distutils.cmd.Command): + + description = ( + "print out package metadata as JSON. This is used by OpenTelemetry dev scripts to ", + "auto-generate code in other places", + ) + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + metadata = { + "name": config["metadata"]["name"], + "version": PACKAGE_INFO["__version__"], + "instruments": PACKAGE_INFO["_instruments"], + } + print(json.dumps(metadata)) + + +setuptools.setup( + cmdclass={"meta": JSONMetadataCommand}, + version=PACKAGE_INFO["__version__"], + extras_require=extras_require, +) diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py new file mode 100644 index 000000000..c9e53d92d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py @@ -0,0 +1,185 @@ +# 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. + +""" +Usage +----- + +* Start broker backend + +:: + + docker run -p 5672:5672 rabbitmq + +* Run instrumented actor + +.. code-block:: python + + from remoulade.brokers.rabbitmq import RabbitmqBroker + import remoulade + + RemouladeInstrumentor().instrument() + + broker = RabbitmqBroker() + remoulade.set_broker(broker) + + @remoulade.actor + def multiply(x, y): + return x * y + + broker.declare_actor(count_words) + + multiply.send(43, 51) + +""" +from typing import Collection + +from remoulade import Middleware, broker + +from opentelemetry import trace +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.remoulade import utils +from opentelemetry.instrumentation.remoulade.package import _instruments +from opentelemetry.instrumentation.remoulade.version import __version__ +from opentelemetry.propagate import extract, inject +from opentelemetry.semconv.trace import SpanAttributes + +_REMOULADE_MESSAGE_TAG_KEY = "remoulade.action" +_REMOULADE_MESSAGE_SEND = "send" +_REMOULADE_MESSAGE_RUN = "run" + +_REMOULADE_MESSAGE_NAME_KEY = "remoulade.actor_name" + +_REMOULADE_MESSAGE_RETRY_COUNT_KEY = "remoulade.retry_count" + + +class _InstrumentationMiddleware(Middleware): + def __init__(self, _tracer): + self._tracer = _tracer + self._span_registry = {} + + def before_process_message(self, _broker, message): + if "trace_ctx" not in message.options: + return + + trace_ctx = extract(message.options["trace_ctx"]) + retry_count = message.options.get("retries", 0) + operation_name = utils.get_operation_name( + "before_process_message", retry_count + ) + span_attributes = {_REMOULADE_MESSAGE_RETRY_COUNT_KEY: retry_count} + + span = self._tracer.start_span( + operation_name, + kind=trace.SpanKind.CONSUMER, + context=trace_ctx, + attributes=span_attributes, + ) + + activation = trace.use_span(span, end_on_exit=True) + activation.__enter__() # pylint: disable=E1101 + + utils.attach_span( + self._span_registry, message.message_id, (span, activation) + ) + + def after_process_message( + self, _broker, message, *, result=None, exception=None + ): + span, activation = utils.retrieve_span( + self._span_registry, message.message_id + ) + + if span is None: + # no existing span found for message_id + return + + if span.is_recording(): + span.set_attributes( + { + _REMOULADE_MESSAGE_TAG_KEY: _REMOULADE_MESSAGE_RUN, + _REMOULADE_MESSAGE_NAME_KEY: message.actor_name, + SpanAttributes.MESSAGING_MESSAGE_ID: message.message_id, + } + ) + + activation.__exit__(None, None, None) + utils.detach_span(self._span_registry, message.message_id) + + def before_enqueue(self, _broker, message, delay): + retry_count = message.options.get("retries", 0) + operation_name = utils.get_operation_name( + "before_enqueue", retry_count + ) + span_attributes = {_REMOULADE_MESSAGE_RETRY_COUNT_KEY: retry_count} + + span = self._tracer.start_span( + operation_name, + kind=trace.SpanKind.PRODUCER, + attributes=span_attributes, + ) + + if span.is_recording(): + span.set_attributes( + { + _REMOULADE_MESSAGE_TAG_KEY: _REMOULADE_MESSAGE_SEND, + _REMOULADE_MESSAGE_NAME_KEY: message.actor_name, + SpanAttributes.MESSAGING_MESSAGE_ID: message.message_id, + } + ) + + activation = trace.use_span(span, end_on_exit=True) + activation.__enter__() # pylint: disable=E1101 + + utils.attach_span( + self._span_registry, + message.message_id, + (span, activation), + is_publish=True, + ) + + if "trace_ctx" not in message.options: + message.options["trace_ctx"] = {} + inject(message.options["trace_ctx"]) + + def after_enqueue(self, _broker, message, delay, exception=None): + _, activation = utils.retrieve_span( + self._span_registry, message.message_id, is_publish=True + ) + + if activation is None: + # no existing span found for message_id + return + + activation.__exit__(None, None, None) + utils.detach_span( + self._span_registry, message.message_id, is_publish=True + ) + + +class RemouladeInstrumentor(BaseInstrumentor): + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + + def _instrument(self, **kwargs): + tracer_provider = kwargs.get("tracer_provider") + + # pylint: disable=attribute-defined-outside-init + self._tracer = trace.get_tracer(__name__, __version__, tracer_provider) + instrumentation_middleware = _InstrumentationMiddleware(self._tracer) + + broker.add_extra_default_middleware(instrumentation_middleware) + + def _uninstrument(self, **kwargs): + broker.remove_extra_default_middleware(_InstrumentationMiddleware) diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/package.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/package.py new file mode 100644 index 000000000..db37739bb --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/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 = ("remoulade >= 0.50",) diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/utils.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/utils.py new file mode 100644 index 000000000..9237f2988 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/utils.py @@ -0,0 +1,43 @@ +# 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. + + +def attach_span( + span_registry, message_id, span_and_activation, is_publish=False +): + span_registry[(message_id, is_publish)] = span_and_activation + + +def detach_span(span_registry, message_id, is_publish=False): + span_registry.pop((message_id, is_publish)) + + +def retrieve_span(span_registry, message_id, is_publish=False): + return span_registry.get((message_id, is_publish), (None, None)) + + +def get_operation_name(hook_name, retry_count): + if hook_name == "before_process_message": + return ( + "remoulade/process" + if retry_count == 0 + else f"remoulade/process(retry-{retry_count})" + ) + if hook_name == "before_enqueue": + return ( + "remoulade/send" + if retry_count == 0 + else f"remoulade/send(retry-{retry_count})" + ) + return "" diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/version.py new file mode 100644 index 000000000..d8dc1e1ed --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/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.31b0" diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-remoulade/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py new file mode 100644 index 000000000..4704111bd --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_messages.py @@ -0,0 +1,100 @@ +# 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 remoulade +from remoulade.brokers.local import LocalBroker + +from opentelemetry.instrumentation.remoulade import RemouladeInstrumentor +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import SpanKind + + +@remoulade.actor(max_retries=3) +def actor_div(dividend, divisor): + return dividend / divisor + + +class TestRemouladeInstrumentation(TestBase): + def setUp(self): + super().setUp() + RemouladeInstrumentor().instrument() + + broker = LocalBroker() + remoulade.set_broker(broker) + + broker.declare_actor(actor_div) + + def test_message(self): + actor_div.send(2, 3) + + spans = self.sorted_spans(self.memory_exporter.get_finished_spans()) + self.assertEqual(len(spans), 2) + + consumer, producer = spans + + self.assertEqual(consumer.name, "remoulade/process") + self.assertEqual(consumer.kind, SpanKind.CONSUMER) + self.assertSpanHasAttributes( + consumer, + { + "remoulade.action": "run", + "remoulade.actor_name": "actor_div", + }, + ) + + self.assertEqual(producer.name, "remoulade/send") + self.assertEqual(producer.kind, SpanKind.PRODUCER) + self.assertSpanHasAttributes( + producer, + { + "remoulade.action": "send", + "remoulade.actor_name": "actor_div", + }, + ) + + self.assertNotEqual(consumer.parent, producer.context) + self.assertEqual(consumer.parent.span_id, producer.context.span_id) + self.assertEqual(consumer.context.trace_id, producer.context.trace_id) + + def test_retries(self): + try: + actor_div.send(1, 0) + except ZeroDivisionError: + pass + + spans = self.sorted_spans(self.memory_exporter.get_finished_spans()) + self.assertEqual(len(spans), 8) + + consumer_spans = spans[::2] + producer_spans = spans[1::2] + + self.assertEqual(consumer_spans[0].name, "remoulade/process(retry-3)") + self.assertSpanHasAttributes( + consumer_spans[0], {"remoulade.retry_count": 3} + ) + self.assertEqual(consumer_spans[1].name, "remoulade/process(retry-2)") + self.assertSpanHasAttributes( + consumer_spans[1], {"remoulade.retry_count": 2} + ) + self.assertEqual(consumer_spans[3].name, "remoulade/process") + + self.assertEqual(producer_spans[0].name, "remoulade/send(retry-3)") + self.assertSpanHasAttributes( + producer_spans[0], {"remoulade.retry_count": 3} + ) + self.assertEqual(producer_spans[1].name, "remoulade/send(retry-2)") + self.assertSpanHasAttributes( + producer_spans[1], {"remoulade.retry_count": 2} + ) + self.assertEqual(producer_spans[3].name, "remoulade/send") diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_uninstrument.py b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_uninstrument.py new file mode 100644 index 000000000..b2b00c3cf --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-remoulade/tests/test_uninstrument.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 remoulade +from remoulade.brokers.local import LocalBroker + +from opentelemetry.instrumentation.remoulade import RemouladeInstrumentor +from opentelemetry.test.test_base import TestBase + + +@remoulade.actor(max_retries=3) +def actor_div(dividend, divisor): + return dividend / divisor + + +class TestRemouladeUninstrumentation(TestBase): + def setUp(self): + super().setUp() + RemouladeInstrumentor().instrument() + + broker = LocalBroker() + remoulade.set_broker(broker) + broker.declare_actor(actor_div) + + RemouladeInstrumentor().uninstrument() + + def test_uninstrument_existing_broker(self): + actor_div.send(1, 1) + spans = self.sorted_spans(self.memory_exporter.get_finished_spans()) + self.assertEqual(len(spans), 0) + + def test_uninstrument_new_brokers(self): + new_broker = LocalBroker() + remoulade.set_broker(new_broker) + new_broker.declare_actor(actor_div) + + actor_div.send(1, 1) + spans = self.sorted_spans(self.memory_exporter.get_finished_spans()) + self.assertEqual(len(spans), 0) + + def test_reinstrument_existing_broker(self): + RemouladeInstrumentor().instrument() + + actor_div.send(1, 1) + spans = self.sorted_spans(self.memory_exporter.get_finished_spans()) + self.assertEqual(len(spans), 2) diff --git a/opentelemetry-contrib-instrumentations/setup.cfg b/opentelemetry-contrib-instrumentations/setup.cfg index 7a1364133..42c1ba348 100644 --- a/opentelemetry-contrib-instrumentations/setup.cfg +++ b/opentelemetry-contrib-instrumentations/setup.cfg @@ -56,6 +56,7 @@ install_requires = opentelemetry-instrumentation-pymysql==0.31b0 opentelemetry-instrumentation-pyramid==0.31b0 opentelemetry-instrumentation-redis==0.31b0 + opentelemetry-instrumentation-remoulade==0.31b0 opentelemetry-instrumentation-requests==0.31b0 opentelemetry-instrumentation-sklearn==0.31b0 opentelemetry-instrumentation-sqlalchemy==0.31b0 diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index e3062cf6b..93d06d329 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -116,6 +116,10 @@ libraries = { "library": "redis >= 2.6", "instrumentation": "opentelemetry-instrumentation-redis==0.31b0", }, + "remoulade": { + "library": "remoulade >= 0.50", + "instrumentation": "opentelemetry-instrumentation-remoulade==0.31b0", + }, "requests": { "library": "requests ~= 2.0", "instrumentation": "opentelemetry-instrumentation-requests==0.31b0", diff --git a/tox.ini b/tox.ini index c698b9266..90988e207 100644 --- a/tox.ini +++ b/tox.ini @@ -153,6 +153,11 @@ envlist = py3{6,7,8,9,10}-test-instrumentation-redis pypy3-test-instrumentation-redis + ; opentelemetry-instrumentation-remoulade + ; remoulade only supports 3.7 and above + py3{7,8,9,10}-test-instrumentation-remoulade + ; instrumentation-remoulade intentionally excluded from pypy3 + ; opentelemetry-instrumentation-celery py3{6,7,8,9,10}-test-instrumentation-celery pypy3-test-instrumentation-celery @@ -275,6 +280,7 @@ changedir = test-instrumentation-pymysql: instrumentation/opentelemetry-instrumentation-pymysql/tests test-instrumentation-pyramid: instrumentation/opentelemetry-instrumentation-pyramid/tests test-instrumentation-redis: instrumentation/opentelemetry-instrumentation-redis/tests + test-instrumentation-remoulade: instrumentation/opentelemetry-instrumentation-remoulade/tests test-instrumentation-requests: instrumentation/opentelemetry-instrumentation-requests/tests test-instrumentation-sklearn: instrumentation/opentelemetry-instrumentation-sklearn/tests test-instrumentation-sqlalchemy{11,14}: instrumentation/opentelemetry-instrumentation-sqlalchemy/tests @@ -354,6 +360,8 @@ commands_pre = redis: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-redis[test] + remoulade: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade[test] + requests: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-requests[test] starlette: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-starlette[test] @@ -448,6 +456,7 @@ commands_pre = python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-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] @@ -497,6 +506,7 @@ deps = requests==2.25.0 pyodbc~=4.0.30 flaky==3.7.0 + remoulade>=0.50 changedir = tests/opentelemetry-docker-tests/tests @@ -519,6 +529,7 @@ commands_pre = -e {toxinidir}/instrumentation/opentelemetry-instrumentation-sqlalchemy \ -e {toxinidir}/instrumentation/opentelemetry-instrumentation-aiopg \ -e {toxinidir}/instrumentation/opentelemetry-instrumentation-redis \ + -e {toxinidir}/instrumentation/opentelemetry-instrumentation-remoulade \ "{env:CORE_REPO}#egg=opentelemetry-exporter-opencensus&subdirectory=exporter/opentelemetry-exporter-opencensus" docker-compose up -d python check_availability.py