From 76170313f162a3a5ac01814192abf69023ae56b3 Mon Sep 17 00:00:00 2001 From: Pete Hodgson Date: Wed, 4 Dec 2024 00:13:07 -0800 Subject: [PATCH 1/2] Fix instrumentation of SQLAlchemy when using sqlalchemy.engine_from_config (#2816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wrap sqlalchemy.engine.create.create_engine sqlalchemy.engine_from_config directly calls create_engine imported from that path; if we don't wrap that copy of the `create_engine` call then engines created via engine_from_config are not instrumented. * add changelog entry * Update CHANGELOG.md Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com> * Update instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py Co-authored-by: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> * make some monkey-patching conditional on the version of SQLAlchemy * lint * fix changelog Signed-off-by: emdneto <9735060+emdneto@users.noreply.github.com> * Update CHANGELOG.md --------- Signed-off-by: emdneto <9735060+emdneto@users.noreply.github.com> Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com> Co-authored-by: Leighton Chen Co-authored-by: Shalev Roda <65566801+shalevr@users.noreply.github.com> Co-authored-by: Tammy Baylis <96076570+tammy-baylis-swi@users.noreply.github.com> Co-authored-by: Riccardo Magliocchetti --- CHANGELOG.md | 2 ++ .../instrumentation/sqlalchemy/__init__.py | 14 ++++++++++++++ .../tests/test_sqlalchemy.py | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a1039f83a..33f83bb0ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3022](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3022)) - Replace all instrumentor unit test `assertEqualSpanInstrumentationInfo` calls with `assertEqualSpanInstrumentationScope` calls ([#3037](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3037)) +- `opentelemetry-instrumentation-sqlalchemy` Fixes engines from `sqlalchemy.engine_from_config` not being fully instrumented + ([#2816](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2816)) - `opentelemetry-instrumentation-sqlalchemy`: Fix a remaining memory leak in EngineTracer ([#3053](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3053)) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py index 9889e18b5a..4182c0034e 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py @@ -181,6 +181,18 @@ def _instrument(self, **kwargs): tracer, connections_usage, enable_commenter, commenter_options ), ) + # sqlalchemy.engine.create is not present in earlier versions of sqlalchemy (which we support) + if parse_version(sqlalchemy.__version__).release >= (1, 4): + _w( + "sqlalchemy.engine.create", + "create_engine", + _wrap_create_engine( + tracer, + connections_usage, + enable_commenter, + commenter_options, + ), + ) _w( "sqlalchemy.engine.base", "Engine.connect", @@ -224,6 +236,8 @@ def _instrument(self, **kwargs): def _uninstrument(self, **kwargs): unwrap(sqlalchemy, "create_engine") unwrap(sqlalchemy.engine, "create_engine") + if parse_version(sqlalchemy.__version__).release >= (1, 4): + unwrap(sqlalchemy.engine.create, "create_engine") unwrap(Engine, "connect") if parse_version(sqlalchemy.__version__).release >= (1, 4): unwrap(sqlalchemy.ext.asyncio, "create_async_engine") diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py index 18b9fa65f7..27a253decb 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py @@ -182,6 +182,17 @@ def test_create_engine_wrapper(self): "opentelemetry.instrumentation.sqlalchemy", ) + def test_instrument_engine_from_config(self): + SQLAlchemyInstrumentor().instrument() + from sqlalchemy import engine_from_config # pylint: disable-all + + engine = engine_from_config({"sqlalchemy.url": "sqlite:///:memory:"}) + cnx = engine.connect() + cnx.execute(text("SELECT 1 + 1;")).fetchall() + spans = self.memory_exporter.get_finished_spans() + + self.assertEqual(len(spans), 2) + def test_create_engine_wrapper_enable_commenter(self): logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) SQLAlchemyInstrumentor().instrument( From 9cf26836bdc998823a10b9809d38a25d3b8c6bfc Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 4 Dec 2024 09:27:56 +0100 Subject: [PATCH 2/2] CONTRIBUTING: notes abount adding doc for new instrumentation (#3064) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CONTRIBUTING: notes abount adding doc for new instrumentation While at it revise the versioning paragraph to take into account the openai instrumentation. * Reword doc paragraph * Update CONTRIBUTING.md Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com> * Add autodoc template * Add notes about tox --------- Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com> --- CONTRIBUTING.md | 6 +++++- _template/autodoc_entry.rst | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 _template/autodoc_entry.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 633a356c40..e90402edc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -272,7 +272,11 @@ Below is a checklist of things to be mindful of when implementing a new instrume - Isolate sync and async test - For synchronous tests, the typical test case class is inherited from `opentelemetry.test.test_base.TestBase`. However, if you want to write asynchronous tests, the test case class should inherit also from `IsolatedAsyncioTestCase`. Adding asynchronous tests to a common test class can lead to tests passing without actually running, which can be misleading. - ex. -- All instrumentations have the same version. If you are going to develop a new instrumentation it would probably have `X.Y.dev` version and depends on `opentelemetry-instrumentation` and `opentelemetry-semantic-conventions` for the same version. That means that if you want to install your instrumentation you need to install its dependencies from this repo and the core repo also from git. +- Most of the instrumentations have the same version. If you are going to develop a new instrumentation it would probably have `X.Y.dev` version and depends on `opentelemetry-instrumentation` and `opentelemetry-semantic-conventions` for a [compatible version](https://peps.python.org/pep-0440/#compatible-release). That means that you may need to install the instrumentation dependencies from this repo and the core repo from git. +- Documentation + - When adding a new instrumentation remember to add an entry in `docs/instrumentation/` named `/.rst` to have the instrumentation documentation referenced from the index. You can use the entry template available [here](./_template/autodoc_entry.rst) +- Testing + - When adding a new instrumentation remember to update `tox.ini` adding appropriate rules in `envlist`, `command_pre` and `commands` sections ## Guideline for GenAI instrumentations diff --git a/_template/autodoc_entry.rst b/_template/autodoc_entry.rst new file mode 100644 index 0000000000..ee2688bacd --- /dev/null +++ b/_template/autodoc_entry.rst @@ -0,0 +1,7 @@ +.. include:: ../../../instrumentation/opentelemetry-instrumentation-/README.rst + :end-before: References + +.. automodule:: opentelemetry.instrumentation. + :members: + :undoc-members: + :show-inheritance: