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

Add docstring for instrument_connection() and tests for database drivers #3108

Merged
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,19 @@
cnx.close()

pool = await aiopg.create_pool(database='Database')

cnx = await pool.acquire()
cursor = await cnx.cursor()
await cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()


cnx = AiopgInstrumentor().instrument_connection(cnx)
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
cursor = await cnx.cursor()
await cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()

API
---
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()

cnx = MySQLInstrumentor().instrument_connection(cnx)
cursor = cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()

API
---
Expand Down Expand Up @@ -86,12 +92,16 @@ def instrument_connection(self, connection, tracer_provider=None):
"""Enable instrumentation in a MySQL connection.

Args:
connection: The connection to instrument.
tracer_provider: The optional tracer provider to use. If omitted
the current globally configured one is used.
connection (mysql.connector.Connection):
The existing MySQL connection instance to instrument. This connection is typically
obtained through `mysql.connector.connect()` and is instrumented to collect telemetry
data about database interactions.
tracer_provider (TracerProvider, optional):
An optional `TracerProvider` instance to use for tracing. If not provided, the globally
configured tracer provider will be automatically used.

Returns:
An instrumented connection.
An instrumented MySQL connection with OpenTelemetry tracing enabled,
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
"""
return dbapi.instrument_connection(
__name__,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@
cnx.commit()
cursor.close()
cnx.close()

instrumented_cnx = MySQLClientInstrumentor.instrument_connection(
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
cnx,
enable_commenter=True,
commenter_options={
"db_driver": True,
"mysql_client_version": True,
"driver_paramstyle": False
}
)
cursor = instrumented_cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)"
instrumented_cnx.commit()
cursor.close()
instrumented_cnx.close()

For example,
::
Expand Down Expand Up @@ -162,12 +177,29 @@ def instrument_connection(
"""Enable instrumentation in a mysqlclient connection.

Args:
connection: The connection to instrument.
tracer_provider: The optional tracer provider to use. If omitted
the current globally configured one is used.

connection (MySQLdb.connect or Connection object):
The MySQL connection instance to instrument. This connection is typically
created using `MySQLdb.connect()` and needs to be wrapped to collect telemetry.
tracer_provider (TracerProvider, optional):
A custom `TracerProvider` instance to be used for tracing. If not specified,
the globally configured tracer provider will be used.
enable_commenter (bool, optional):
A flag to enable the OpenTelemetry SQLCommenter feature. If set to `True`,
SQL queries will be enriched with contextual information (e.g., database client details).
Default is `None`.
commenter_options (dict, optional):
A dictionary of configuration options for SQLCommenter. This allows you to customize
metadata appended to queries. Possible options include:
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
- `db_driver`: Adds the database driver name and version.
- `dbapi_threadsafety`: Adds threadsafety information.
- `dbapi_level`: Adds the DB-API version.
- `mysql_client_version`: Adds the MySQL client version.
- `driver_paramstyle`: Adds the parameter style.
- `opentelemetry_values`: Includes traceparent values.
Refer to *SQLCommenter Configurations* above for more information

Returns:
An instrumented connection.
An instrumented MySQL connection with OpenTelemetry support enabled.
"""

return dbapi.instrument_connection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,18 @@
PsycopgInstrumentor().instrument()

cnx = psycopg.connect(database='Database')

cursor = cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()


instrumented_cnx = instrument_connection(cnx)
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
cursor = instrumented_cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
instrumented_cnx.close()

API
---
"""
Expand Down Expand Up @@ -196,6 +203,18 @@ def _uninstrument(self, **kwargs):
# TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql
@staticmethod
def instrument_connection(connection, tracer_provider=None):
"""Enable instrumentation in a psycopg connection.

Args:
connection: psycopg.Connection
The psycopg connection object to be instrumented.
tracer_provider: opentelemetry.trace.TracerProvider, optional
The TracerProvider to use for instrumentation. If not provided,
the global TracerProvider will be used.

Returns:
An instrumented psycopg connection object.
"""
if not hasattr(connection, "_is_instrumented_by_opentelemetry"):
connection._is_instrumented_by_opentelemetry = False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,17 @@
Psycopg2Instrumentor().instrument()

cnx = psycopg2.connect(database='Database')

cursor = cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()

instrumented_cnx = Psycopg2Instrumentor.instrument_connection(cnx)
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
cursor = instrumented_cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
instrumented_cnx.close()
API
---
"""
Expand Down Expand Up @@ -160,6 +166,19 @@ def _uninstrument(self, **kwargs):
# TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql
@staticmethod
def instrument_connection(connection, tracer_provider=None):
"""Enable instrumentation in a psycopg2 connection.

Args:
connection: psycopg2.extensions.connection
The psycopg2 connection object to be instrumented.
tracer_provider: opentelemetry.trace.TracerProvider, optional
The TracerProvider to use for instrumentation. If not specified,
the global TracerProvider will be used.

Returns:
An instrumented psycopg2 connection object.
"""

if not hasattr(connection, "_is_instrumented_by_opentelemetry"):
connection._is_instrumented_by_opentelemetry = False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@
cnx.commit()
cursor.close()
cnx.close()

instrumented_cnx = PyMySQLInstrumentor().instrument_connection(
cnx,
enable_commenter=True,
commenter_options={
"db_driver": True,
"mysql_client_version": True
}
)
cursor = instrumented_cnx.cursor()
cursor.execute("INSERT INTO test (testField) VALUES (123)"
instrumented_cnx.commit()
cursor.close()
instrumented_cnx.close()


For example,
Expand Down Expand Up @@ -165,10 +179,20 @@ def instrument_connection(
"""Enable instrumentation in a PyMySQL connection.

Args:
connection: The connection to instrument.
tracer_provider: The optional tracer provider to use. If omitted
the current globally configured one is used.

connection (pymysql.Connection):
The existing PyMySQL connection instance that needs to be instrumented.
This connection was typically created using `pymysql.connect()` and is wrapped with OpenTelemetry tracing.
tracer_provider (TracerProvider, optional):
An optional `TracerProvider` instance that specifies which tracer provider should be used.
If not provided, the globally configured OpenTelemetry tracer provider is automatically applied.
enable_commenter (bool, optional):
A flag to enable the SQL Commenter feature. If `True`, query logs will be enriched with additional
contextual metadata (e.g., database version, traceparent IDs, driver information).
commenter_options (dict, optional):
A dictionary containing configuration options for the SQL Commenter feature.
You can specify various options, such as enabling driver information, database version logging,
traceparent propagation, and other customizable metadata enhancements.
See *SQLCommenter Configurations* above for more information.
Returns:
An instrumented connection.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,22 @@
SQLite3Instrumentor().instrument()

cnx = sqlite3.connect(':memory:')

cursor = cnx.cursor()
cursor.execute("CREATE TABLE test (testField INTEGER)")
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.close()
cnx.close()

conn = sqlite3.connect(":memory:")

instrumented_connection = SQLite3Instrumentor.instrument_connection(conn)
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
cursor = instrumented_connection.cursor()
cursor.execute("CREATE TABLE test (testField INTEGER)")
cursor.execute("INSERT INTO test (testField) VALUES (123)")
cursor.execute("SELECT * FROM test")
cursor.close()
instrumented_connection.close()

API
---
Expand Down Expand Up @@ -104,7 +115,13 @@ def instrument_connection(
the current globally configured one is used.

Returns:
An instrumented connection.
SQLite3Connection: An instrumented SQLite connection that supports
telemetry for tracing database operations.

Notes:
- Instrumentation must be explicitly applied to the connection object
for tracing to work. This is not done automatically by simply calling
`SQLite3Instrumentor().instrument()`.
"""

return dbapi.instrument_connection(
Expand All @@ -129,3 +146,4 @@ def uninstrument_connection(
An uninstrumented connection.
"""
return dbapi.uninstrument_connection(connection)

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def setUp(self):
self._cursor = self._connection.cursor()
self._connection2 = dbapi2.connect(":memory:")
self._cursor2 = self._connection2.cursor()
self._connection3 = SQLite3Instrumentor.instrument_connection(dbapi2.connect(":memory:"))
tammy-baylis-swi marked this conversation as resolved.
Show resolved Hide resolved
self._cursor3 = self._connection3.cursor()

def tearDown(self):
super().tearDown()
Expand All @@ -40,6 +42,10 @@ def tearDown(self):
self._cursor2.close()
if self._connection2:
self._connection2.close()
if self._cursor3:
self._cursor3.close()
if self._connection3:
self._connection3.close()
SQLite3Instrumentor().uninstrument()

def validate_spans(self, span_name):
Expand All @@ -65,6 +71,7 @@ def _create_tables(self):
stmt = "CREATE TABLE IF NOT EXISTS test (id integer)"
self._cursor.execute(stmt)
self._cursor2.execute(stmt)
self._cursor3.execute(stmt)
self.memory_exporter.clear()

def test_execute(self):
Expand All @@ -77,6 +84,10 @@ def test_execute(self):
with self._tracer.start_as_current_span("rootSpan"):
self._cursor2.execute(stmt)
self.validate_spans("CREATE")

with self._tracer.start_as_current_span("rootSpan"):
self._cursor3.execute(stmt)
self.validate_spans("CREATE")

def test_executemany(self):
"""Should create a child span for executemany"""
Expand All @@ -93,10 +104,15 @@ def test_executemany(self):
self._cursor2.executemany(stmt, data)
self.validate_spans("INSERT")

with self._tracer.start_as_current_span("rootSpan"):
self._cursor3.executemany(stmt, data)
self.validate_spans("INSERT")

def test_callproc(self):
"""Should create a child span for callproc"""
with self._tracer.start_as_current_span("rootSpan"), self.assertRaises(
Exception
):
self._cursor.callproc("test", ())
self.validate_spans("test")

Loading