mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-31 22:23:12 +08:00
(instrumentation-sqlite3): trace connections made with dbapi2.connect
(#873)
* Change wrap_connect method * Wrap both connect defs * Add tests * Add CHANGELOG entry
This commit is contained in:
@ -34,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- `opentelemetry-instrumentation-django` Django: fix issue preventing detection of MIDDLEWARE_CLASSES
|
- `opentelemetry-instrumentation-django` Django: fix issue preventing detection of MIDDLEWARE_CLASSES
|
||||||
|
|
||||||
|
- `opentelemetry-instrumentation-sqlite3` Instrumentation now works with `dbapi2.connect`
|
||||||
|
|
||||||
## [1.8.0-0.27b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.8.0-0.27b0) - 2021-12-17
|
## [1.8.0-0.27b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.8.0-0.27b0) - 2021-12-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -40,6 +40,7 @@ API
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from sqlite3 import dbapi2
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
|
|
||||||
from opentelemetry.instrumentation import dbapi
|
from opentelemetry.instrumentation import dbapi
|
||||||
@ -54,6 +55,8 @@ _DATABASE_SYSTEM = "sqlite"
|
|||||||
|
|
||||||
|
|
||||||
class SQLite3Instrumentor(BaseInstrumentor):
|
class SQLite3Instrumentor(BaseInstrumentor):
|
||||||
|
_TO_WRAP = [sqlite3, dbapi2]
|
||||||
|
|
||||||
def instrumentation_dependencies(self) -> Collection[str]:
|
def instrumentation_dependencies(self) -> Collection[str]:
|
||||||
return _instruments
|
return _instruments
|
||||||
|
|
||||||
@ -63,19 +66,21 @@ class SQLite3Instrumentor(BaseInstrumentor):
|
|||||||
"""
|
"""
|
||||||
tracer_provider = kwargs.get("tracer_provider")
|
tracer_provider = kwargs.get("tracer_provider")
|
||||||
|
|
||||||
dbapi.wrap_connect(
|
for module in self._TO_WRAP:
|
||||||
__name__,
|
dbapi.wrap_connect(
|
||||||
sqlite3,
|
__name__,
|
||||||
"connect",
|
module,
|
||||||
_DATABASE_SYSTEM,
|
"connect",
|
||||||
_CONNECTION_ATTRIBUTES,
|
_DATABASE_SYSTEM,
|
||||||
version=__version__,
|
_CONNECTION_ATTRIBUTES,
|
||||||
tracer_provider=tracer_provider,
|
version=__version__,
|
||||||
)
|
tracer_provider=tracer_provider,
|
||||||
|
)
|
||||||
|
|
||||||
def _uninstrument(self, **kwargs):
|
def _uninstrument(self, **kwargs):
|
||||||
""" "Disable SQLite3 instrumentation"""
|
""" "Disable SQLite3 instrumentation"""
|
||||||
dbapi.unwrap_connect(sqlite3, "connect")
|
for module in self._TO_WRAP:
|
||||||
|
dbapi.unwrap_connect(module, "connect")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def instrument_connection(connection, tracer_provider=None):
|
def instrument_connection(connection, tracer_provider=None):
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from sqlite3 import dbapi2
|
||||||
|
|
||||||
from opentelemetry import trace as trace_api
|
from opentelemetry import trace as trace_api
|
||||||
from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor
|
from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor
|
||||||
@ -25,10 +26,14 @@ class TestSQLite3(TestBase):
|
|||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
cls._connection = None
|
cls._connection = None
|
||||||
cls._cursor = None
|
cls._cursor = None
|
||||||
|
cls._connection2 = None
|
||||||
|
cls._cursor2 = None
|
||||||
cls._tracer = cls.tracer_provider.get_tracer(__name__)
|
cls._tracer = cls.tracer_provider.get_tracer(__name__)
|
||||||
SQLite3Instrumentor().instrument(tracer_provider=cls.tracer_provider)
|
SQLite3Instrumentor().instrument(tracer_provider=cls.tracer_provider)
|
||||||
cls._connection = sqlite3.connect(":memory:")
|
cls._connection = sqlite3.connect(":memory:")
|
||||||
cls._cursor = cls._connection.cursor()
|
cls._cursor = cls._connection.cursor()
|
||||||
|
cls._connection2 = dbapi2.connect(":memory:")
|
||||||
|
cls._cursor2 = cls._connection2.cursor()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
@ -36,9 +41,14 @@ class TestSQLite3(TestBase):
|
|||||||
cls._cursor.close()
|
cls._cursor.close()
|
||||||
if cls._connection:
|
if cls._connection:
|
||||||
cls._connection.close()
|
cls._connection.close()
|
||||||
|
if cls._cursor2:
|
||||||
|
cls._cursor2.close()
|
||||||
|
if cls._connection2:
|
||||||
|
cls._connection2.close()
|
||||||
|
|
||||||
def validate_spans(self, span_name):
|
def validate_spans(self, span_name):
|
||||||
spans = self.memory_exporter.get_finished_spans()
|
spans = self.memory_exporter.get_finished_spans()
|
||||||
|
self.memory_exporter.clear()
|
||||||
self.assertEqual(len(spans), 2)
|
self.assertEqual(len(spans), 2)
|
||||||
for span in spans:
|
for span in spans:
|
||||||
if span.name == "rootSpan":
|
if span.name == "rootSpan":
|
||||||
@ -62,14 +72,22 @@ class TestSQLite3(TestBase):
|
|||||||
self._cursor.execute(stmt)
|
self._cursor.execute(stmt)
|
||||||
self.validate_spans("CREATE")
|
self.validate_spans("CREATE")
|
||||||
|
|
||||||
|
with self._tracer.start_as_current_span("rootSpan"):
|
||||||
|
self._cursor2.execute(stmt)
|
||||||
|
self.validate_spans("CREATE")
|
||||||
|
|
||||||
def test_executemany(self):
|
def test_executemany(self):
|
||||||
"""Should create a child span for executemany"""
|
"""Should create a child span for executemany"""
|
||||||
stmt = "INSERT INTO test (id) VALUES (?)"
|
stmt = "INSERT INTO test (id) VALUES (?)"
|
||||||
|
data = [("1",), ("2",), ("3",)]
|
||||||
with self._tracer.start_as_current_span("rootSpan"):
|
with self._tracer.start_as_current_span("rootSpan"):
|
||||||
data = [("1",), ("2",), ("3",)]
|
|
||||||
self._cursor.executemany(stmt, data)
|
self._cursor.executemany(stmt, data)
|
||||||
self.validate_spans("INSERT")
|
self.validate_spans("INSERT")
|
||||||
|
|
||||||
|
with self._tracer.start_as_current_span("rootSpan"):
|
||||||
|
self._cursor2.executemany(stmt, data)
|
||||||
|
self.validate_spans("INSERT")
|
||||||
|
|
||||||
def test_callproc(self):
|
def test_callproc(self):
|
||||||
"""Should create a child span for callproc"""
|
"""Should create a child span for callproc"""
|
||||||
with self._tracer.start_as_current_span("rootSpan"), self.assertRaises(
|
with self._tracer.start_as_current_span("rootSpan"), self.assertRaises(
|
||||||
|
Reference in New Issue
Block a user