From 385606a5ca1941311155454d8791c98e9246c974 Mon Sep 17 00:00:00 2001 From: Thiyagu55 Date: Thu, 28 Jul 2022 12:51:44 +0530 Subject: [PATCH 1/4] Adding commenter_options in sqlalchemy commenter --- .../instrumentation/sqlalchemy/__init__.py | 38 +++++++++++++++++++ .../instrumentation/sqlalchemy/engine.py | 24 ++++++++++-- .../tests/test_sqlcommenter.py | 3 +- 3 files changed, 61 insertions(+), 4 deletions(-) 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 bc438c609a..e171aafee9 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py @@ -22,6 +22,41 @@ .. _sqlalchemy: https://pypi.org/project/sqlalchemy/ +SQLCOMMENTER +***************************************** +You can optionally configure SQLAlchemy instrumentation to enable sqlcommenter which enriches +the query with contextual information. + +Usage +----- +.. code:: python + from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor + SQLAlchemyInstrumentor().instrument(enable_commenter=True, commenter_options={}) + +For example, +:: +Invoking engine.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter is enabled +the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" + +SQLCommenter Configurations +*************************** +We can configure the tags to be appended to the sqlquery log by adding configuration inside commenter_options(default:{}) keyword + +db_driver = True(Default) or False +For example, +:: +Enabling this flag will add any underlying driver like psycopg2 /*db_driver='psycopg2'*/ + +db_framework = True(Default) or False +For example, +:: +Enabling this flag will add db_framework and it's version /*db_framework='sqlalchemy:0.41b0'*/ + +opentelemetry_values = True(Default) or False +For example, +:: +Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ + Usage ----- .. code:: python @@ -115,6 +150,8 @@ def _instrument(self, **kwargs): _get_tracer(tracer_provider), kwargs.get("engine"), kwargs.get("enable_commenter", False), + kwargs.get("commenter_options", {}), + ) if kwargs.get("engines") is not None and isinstance( kwargs.get("engines"), Sequence @@ -124,6 +161,7 @@ def _instrument(self, **kwargs): _get_tracer(tracer_provider), engine, kwargs.get("enable_commenter", False), + kwargs.get("commenter_options", {}), ) for engine in kwargs.get("engines") ] diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index 25e8791dc8..e9f261d61c 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -94,11 +94,12 @@ def _wrap_connect_internal(func, module, args, kwargs): class EngineTracer: - def __init__(self, tracer, engine, enable_commenter=False): + def __init__(self, tracer, engine, enable_commenter=True, commenter_options={}): self.tracer = tracer self.engine = engine self.vendor = _normalize_vendor(engine.name) self.enable_commenter = enable_commenter + self.commenter_options = commenter_options listen( engine, "before_cursor_execute", self._before_cur_exec, retval=True @@ -141,8 +142,25 @@ def _before_cur_exec( for key, value in attrs.items(): span.set_attribute(key, value) if self.enable_commenter: - commenter_data = {} - commenter_data.update(_get_opentelemetry_values()) + commenter_data = dict( + db_driver=conn.engine.driver, + # Driver/framework centric information. + db_framework=f"sqlalchemy:{__version__}", + ) + + if self.commenter_options.get( + "opentelemetry_values", True + ): + commenter_data.update(**_get_opentelemetry_values()) + + # Filter down to just the requested attributes. + commenter_data = { + k: v + for k, v in commenter_data.items() + if self.commenter_options.get(k, True) + } + commenter_data = {k: v for k, v in commenter_data.items() if self.commenter_options.get(k, True)} + statement = _add_sql_comment(statement, **commenter_data) context._otel_span = span diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py index 8245d990f7..0775367963 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py @@ -46,10 +46,11 @@ def test_sqlcommenter_enabled(self): engine=engine, tracer_provider=self.tracer_provider, enable_commenter=True, + commenter_options={'db_framework': False}, ) cnx = engine.connect() cnx.execute("SELECT 1;").fetchall() self.assertRegex( self.caplog.records[-2].getMessage(), - r"SELECT 1 /\*traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", + r"SELECT 1 /\*db_driver='(.*)',traceparent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;", ) From 4ade82b8a0495ec5dacd871f78c018d936604e53 Mon Sep 17 00:00:00 2001 From: Thiyagu55 Date: Thu, 28 Jul 2022 15:45:56 +0530 Subject: [PATCH 2/4] Linting changes --- CHANGELOG.md | 2 ++ .../instrumentation/sqlalchemy/__init__.py | 13 ++++++++++--- .../instrumentation/sqlalchemy/engine.py | 9 ++++----- .../tests/test_sqlcommenter.py | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 793568e433..7bfda25c43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1187](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1187)) - SQLCommenter semicolon bug fix ([#1200](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1200/files)) +- Adding sqlalchemy native tags in sqlalchemy commenter + ([#1206](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1206)) ### Added - `opentelemetry-instrumentation-redis` add support to instrument RedisCluster clients 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 e171aafee9..3f0c61ee74 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py @@ -29,30 +29,38 @@ Usage ----- + .. code:: python + from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor + SQLAlchemyInstrumentor().instrument(enable_commenter=True, commenter_options={}) + For example, :: -Invoking engine.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter is enabled -the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" + + Invoking engine.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter is enabled + the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" SQLCommenter Configurations *************************** We can configure the tags to be appended to the sqlquery log by adding configuration inside commenter_options(default:{}) keyword db_driver = True(Default) or False + For example, :: Enabling this flag will add any underlying driver like psycopg2 /*db_driver='psycopg2'*/ db_framework = True(Default) or False + For example, :: Enabling this flag will add db_framework and it's version /*db_framework='sqlalchemy:0.41b0'*/ opentelemetry_values = True(Default) or False + For example, :: Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/ @@ -151,7 +159,6 @@ def _instrument(self, **kwargs): kwargs.get("engine"), kwargs.get("enable_commenter", False), kwargs.get("commenter_options", {}), - ) if kwargs.get("engines") is not None and isinstance( kwargs.get("engines"), Sequence diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index e9f261d61c..ff8fc6d7c9 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -94,7 +94,9 @@ def _wrap_connect_internal(func, module, args, kwargs): class EngineTracer: - def __init__(self, tracer, engine, enable_commenter=True, commenter_options={}): + def __init__( + self, tracer, engine, enable_commenter=True, commenter_options=None + ): self.tracer = tracer self.engine = engine self.vendor = _normalize_vendor(engine.name) @@ -148,9 +150,7 @@ def _before_cur_exec( db_framework=f"sqlalchemy:{__version__}", ) - if self.commenter_options.get( - "opentelemetry_values", True - ): + if self.commenter_options.get("opentelemetry_values", True): commenter_data.update(**_get_opentelemetry_values()) # Filter down to just the requested attributes. @@ -159,7 +159,6 @@ def _before_cur_exec( for k, v in commenter_data.items() if self.commenter_options.get(k, True) } - commenter_data = {k: v for k, v in commenter_data.items() if self.commenter_options.get(k, True)} statement = _add_sql_comment(statement, **commenter_data) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py index 0775367963..616388f5e5 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlcommenter.py @@ -46,7 +46,7 @@ def test_sqlcommenter_enabled(self): engine=engine, tracer_provider=self.tracer_provider, enable_commenter=True, - commenter_options={'db_framework': False}, + commenter_options={"db_framework": False}, ) cnx = engine.connect() cnx.execute("SELECT 1;").fetchall() From 5846a6533a392e8c94679283486b04a31aa24758 Mon Sep 17 00:00:00 2001 From: Thiyagu55 Date: Thu, 28 Jul 2022 15:53:27 +0530 Subject: [PATCH 3/4] Linting changes --- .../src/opentelemetry/instrumentation/sqlalchemy/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py index ff8fc6d7c9..7441c0aa03 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py @@ -101,7 +101,7 @@ def __init__( self.engine = engine self.vendor = _normalize_vendor(engine.name) self.enable_commenter = enable_commenter - self.commenter_options = commenter_options + self.commenter_options = commenter_options if commenter_options else {} listen( engine, "before_cursor_execute", self._before_cur_exec, retval=True From 20c76e258ee00fad4b9ef5f034f67cf43fa67868 Mon Sep 17 00:00:00 2001 From: Thiyagu55 Date: Wed, 3 Aug 2022 10:48:09 +0530 Subject: [PATCH 4/4] Docs changes --- .../src/opentelemetry/instrumentation/sqlalchemy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3f0c61ee74..e56485ca77 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py @@ -23,7 +23,7 @@ .. _sqlalchemy: https://pypi.org/project/sqlalchemy/ SQLCOMMENTER -***************************************** +**************************************** You can optionally configure SQLAlchemy instrumentation to enable sqlcommenter which enriches the query with contextual information.