Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DB drivers: db.statement inclusion of sqlcomment as opt-in #3121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115))


### Breaking changes

- `opentelemetry-instrumentation-dbapi` including sqlcomment in `db.statement` span attribute value is now opt-in
([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115))
- `opentelemetry-instrumentation-psycopg2`, `opentelemetry-instrumentation-psycopg`, `opentelemetry-instrumentation-mysqlclient`, `opentelemetry-instrumentation-pymysql`: including sqlcomment in `db.statement` span attribute value is now opt-in
([#3121](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3121))


## Version 1.29.0/0.50b0 (2024-12-11)

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,26 @@
::
Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/

SQLComment in span attribute
****************************
If sqlcommenter is enabled, you can optionally configure MySQLClient instrumentation to append sqlcomment to query span attribute for convenience of your platform.

.. code:: python

from opentelemetry.instrumentation.mysqlclient import MySQLClientInstrumentor

MySQLClientInstrumentor().instrument(
enable_commenter=True,
enable_attribute_commenter=True,
)


For example,
::

Invoking cursor.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled
the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute.

API
---
"""
Expand Down Expand Up @@ -159,6 +179,9 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use
tracer_provider = kwargs.get("tracer_provider")
enable_sqlcommenter = kwargs.get("enable_commenter", False)
commenter_options = kwargs.get("commenter_options", {})
enable_attribute_commenter = kwargs.get(
"enable_attribute_commenter", False
)

dbapi.wrap_connect(
__name__,
Expand All @@ -170,6 +193,7 @@ def _instrument(self, **kwargs): # pylint: disable=no-self-use
tracer_provider=tracer_provider,
enable_commenter=enable_sqlcommenter,
commenter_options=commenter_options,
enable_attribute_commenter=enable_attribute_commenter,
)

def _uninstrument(self, **kwargs): # pylint: disable=no-self-use
Expand All @@ -182,6 +206,7 @@ def instrument_connection(
tracer_provider=None,
enable_commenter=None,
commenter_options=None,
enable_attribute_commenter=None,
):
"""Enable instrumentation in a mysqlclient connection.

Expand Down Expand Up @@ -220,6 +245,7 @@ def instrument_connection(
enable_commenter=enable_commenter,
commenter_options=commenter_options,
connect_module=MySQLdb,
enable_attribute_commenter=enable_attribute_commenter,
)

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import opentelemetry.instrumentation.mysqlclient
from opentelemetry.instrumentation.mysqlclient import MySQLClientInstrumentor
from opentelemetry.sdk import resources
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.test_base import TestBase


Expand Down Expand Up @@ -110,12 +111,14 @@ def test_instrument_connection_enable_commenter_dbapi_kwargs(
cnx,
enable_commenter=True,
commenter_options={"foo": True},
enable_attribute_commenter=True,
)
cursor = cnx.cursor()
cursor.execute("Select 1;")
kwargs = mock_instrument_connection.call_args[1]
self.assertEqual(kwargs["enable_commenter"], True)
self.assertEqual(kwargs["commenter_options"], {"foo": True})
self.assertEqual(kwargs["enable_attribute_commenter"], True)

def test_instrument_connection_with_dbapi_sqlcomment_enabled(self):
mock_connect_module = mock.MagicMock(
Expand Down Expand Up @@ -150,6 +153,51 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled(self):
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

def test_instrument_connection_with_dbapi_sqlcomment_enabled_stmt_enabled(
self,
):
mock_connect_module = mock.MagicMock(
__name__="MySQLdb",
threadsafety="123",
apilevel="123",
paramstyle="test",
)
mock_connect_module._mysql.get_client_info.return_value = "foobaz"
mock_cursor = mock_connect_module.connect().cursor()
mock_connection = mock.MagicMock()
mock_connection.cursor.return_value = mock_cursor

with mock.patch(
"opentelemetry.instrumentation.mysqlclient.MySQLdb",
mock_connect_module,
), mock.patch(
"opentelemetry.instrumentation.dbapi.util_version",
return_value="foobar",
):
cnx_proxy = MySQLClientInstrumentor().instrument_connection(
mock_connection,
enable_commenter=True,
enable_attribute_commenter=True,
)
cnx_proxy.cursor().execute("Select 1;")

spans_list = self.memory_exporter.get_finished_spans()
span = spans_list[0]
span_id = format(span.get_span_context().span_id, "016x")
trace_id = format(span.get_span_context().trace_id, "032x")
self.assertEqual(
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)

def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options(
self,
Expand Down Expand Up @@ -191,6 +239,10 @@ def test_instrument_connection_with_dbapi_sqlcomment_enabled_with_options(
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default(
self,
Expand Down Expand Up @@ -221,6 +273,12 @@ def test_instrument_connection_with_dbapi_sqlcomment_not_enabled_default(
mock_cursor.execute.call_args[0][0],
"Select 1;",
)
spans_list = self.memory_exporter.get_finished_spans()
span = spans_list[0]
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

@mock.patch("opentelemetry.instrumentation.dbapi.wrap_connect")
@mock.patch("MySQLdb.connect")
Expand All @@ -233,10 +291,12 @@ def test_instrument_enable_commenter_dbapi_kwargs(
MySQLClientInstrumentor()._instrument(
enable_commenter=True,
commenter_options={"foo": True},
enable_attribute_commenter=True,
)
kwargs = mock_wrap_connect.call_args[1]
self.assertEqual(kwargs["enable_commenter"], True)
self.assertEqual(kwargs["commenter_options"], {"foo": True})
self.assertEqual(kwargs["enable_attribute_commenter"], True)

def test_instrument_with_dbapi_sqlcomment_enabled(
self,
Expand Down Expand Up @@ -274,6 +334,52 @@ def test_instrument_with_dbapi_sqlcomment_enabled(
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

def test_instrument_with_dbapi_sqlcomment_enabled_stmt_enabled(
self,
):
mock_connect_module = mock.MagicMock(
__name__="MySQLdb",
threadsafety="123",
apilevel="123",
paramstyle="test",
)
mock_connect_module._mysql.get_client_info.return_value = "foobaz"
mock_cursor = mock_connect_module.connect().cursor()
mock_connection = mock.MagicMock()
mock_connection.cursor.return_value = mock_cursor

with mock.patch(
"opentelemetry.instrumentation.mysqlclient.MySQLdb",
mock_connect_module,
), mock.patch(
"opentelemetry.instrumentation.dbapi.util_version",
return_value="foobar",
):
MySQLClientInstrumentor()._instrument(
enable_commenter=True,
enable_attribute_commenter=True,
)
cnx = mock_connect_module.connect(database="test")
cursor = cnx.cursor()
cursor.execute("Select 1;")

spans_list = self.memory_exporter.get_finished_spans()
span = spans_list[0]
span_id = format(span.get_span_context().span_id, "016x")
trace_id = format(span.get_span_context().trace_id, "032x")
self.assertEqual(
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)

def test_instrument_with_dbapi_sqlcomment_enabled_with_options(
self,
Expand Down Expand Up @@ -316,6 +422,10 @@ def test_instrument_with_dbapi_sqlcomment_enabled_with_options(
mock_cursor.execute.call_args[0][0],
f"Select 1 /*db_driver='MySQLdb%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
)
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

def test_instrument_with_dbapi_sqlcomment_not_enabled_default(
self,
Expand Down Expand Up @@ -346,6 +456,12 @@ def test_instrument_with_dbapi_sqlcomment_not_enabled_default(
mock_cursor.execute.call_args[0][0],
"Select 1;",
)
spans_list = self.memory_exporter.get_finished_spans()
span = spans_list[0]
self.assertEqual(
span.attributes[SpanAttributes.DB_STATEMENT],
"Select 1;",
)

@mock.patch("MySQLdb.connect")
# pylint: disable=unused-argument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@
::
Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/

SQLComment in span attribute
****************************
If sqlcommenter is enabled, you can optionally configure psycopg instrumentation to append sqlcomment to query span attribute for convenience of your platform.

.. code:: python

from opentelemetry.instrumentation.psycopg import PsycopgInstrumentor

PsycopgInstrumentor().instrument(
enable_commenter=True,
enable_attribute_commenter=True,
)


For example,
::

Invoking cursor.execute("select * from auth_users") will lead to postgresql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled
the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute.

Usage
-----

Expand Down Expand Up @@ -159,6 +179,9 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
enable_sqlcommenter = kwargs.get("enable_commenter", False)
commenter_options = kwargs.get("commenter_options", {})
enable_attribute_commenter = kwargs.get(
"enable_attribute_commenter", False
)
dbapi.wrap_connect(
__name__,
psycopg,
Expand All @@ -170,6 +193,7 @@ def _instrument(self, **kwargs):
db_api_integration_factory=DatabaseApiIntegration,
enable_commenter=enable_sqlcommenter,
commenter_options=commenter_options,
enable_attribute_commenter=enable_attribute_commenter,
)

dbapi.wrap_connect(
Expand All @@ -183,6 +207,7 @@ def _instrument(self, **kwargs):
db_api_integration_factory=DatabaseApiIntegration,
enable_commenter=enable_sqlcommenter,
commenter_options=commenter_options,
enable_attribute_commenter=enable_attribute_commenter,
)
dbapi.wrap_connect(
__name__,
Expand All @@ -195,6 +220,7 @@ def _instrument(self, **kwargs):
db_api_integration_factory=DatabaseApiAsyncIntegration,
enable_commenter=enable_sqlcommenter,
commenter_options=commenter_options,
enable_attribute_commenter=enable_attribute_commenter,
)

def _uninstrument(self, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@
::
Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/

SQLComment in span attribute
****************************
If sqlcommenter is enabled, you can optionally configure psycopg2 instrumentation to append sqlcomment to query span attribute for convenience of your platform.

.. code:: python

from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor

Psycopg2Instrumentor().instrument(
enable_commenter=True,
enable_attribute_commenter=True,
)


For example,
::

Invoking cursor.execute("select * from auth_users") will lead to postgresql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled
the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute.

Usage
-----

Expand Down Expand Up @@ -156,6 +176,9 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
enable_sqlcommenter = kwargs.get("enable_commenter", False)
commenter_options = kwargs.get("commenter_options", {})
enable_attribute_commenter = kwargs.get(
"enable_attribute_commenter", False
)
dbapi.wrap_connect(
__name__,
psycopg2,
Expand All @@ -167,6 +190,7 @@ def _instrument(self, **kwargs):
db_api_integration_factory=DatabaseApiIntegration,
enable_commenter=enable_sqlcommenter,
commenter_options=commenter_options,
enable_attribute_commenter=enable_attribute_commenter,
)

def _uninstrument(self, **kwargs):
Expand Down
Loading
Loading