Skip to content

Commit 69d1ea3

Browse files
Fix psycopg2 instrument_connection
1 parent 5c5fc73 commit 69d1ea3

File tree

1 file changed

+42
-22
lines changed
  • instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2

1 file changed

+42
-22
lines changed

instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,19 @@
106106
from typing import Collection
107107

108108
import psycopg2
109+
import wrapt
109110
from psycopg2.extensions import (
110111
cursor as pg_cursor, # pylint: disable=no-name-in-module
111112
)
112113
from psycopg2.sql import Composed # pylint: disable=no-name-in-module
113114

115+
from opentelemetry import trace as trace_api
114116
from opentelemetry.instrumentation import dbapi
115117
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
116118
from opentelemetry.instrumentation.psycopg2.package import _instruments
117119
from opentelemetry.instrumentation.psycopg2.version import __version__
118120

119121
_logger = logging.getLogger(__name__)
120-
_OTEL_CURSOR_FACTORY_KEY = "_otel_orig_cursor_factory"
121122

122123

123124
class Psycopg2Instrumentor(BaseInstrumentor):
@@ -130,6 +131,8 @@ class Psycopg2Instrumentor(BaseInstrumentor):
130131

131132
_DATABASE_SYSTEM = "postgresql"
132133

134+
_otel_cursor_factory = None
135+
133136
def instrumentation_dependencies(self) -> Collection[str]:
134137
return _instruments
135138

@@ -158,32 +161,40 @@ def _uninstrument(self, **kwargs):
158161
dbapi.unwrap_connect(psycopg2, "connect")
159162

160163
# TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql
161-
@staticmethod
162-
def instrument_connection(connection, tracer_provider=None):
163-
if not hasattr(connection, "_is_instrumented_by_opentelemetry"):
164-
connection._is_instrumented_by_opentelemetry = False
165-
166-
if not connection._is_instrumented_by_opentelemetry:
167-
setattr(
168-
connection, _OTEL_CURSOR_FACTORY_KEY, connection.cursor_factory
169-
)
170-
connection.cursor_factory = _new_cursor_factory(
171-
tracer_provider=tracer_provider
172-
)
173-
connection._is_instrumented_by_opentelemetry = True
174-
else:
164+
def instrument_connection(
165+
self,
166+
connection,
167+
tracer_provider: typing.Optional[trace_api.TracerProvider] = None,
168+
enable_commenter: bool = False,
169+
commenter_options: dict = None,
170+
):
171+
if isinstance(connection, wrapt.ObjectProxy):
172+
# The connection is already instrumented from wrapt.wrap_function_wrapper
173+
# of the psycopg2 module's `connect` method by DB-API `wrap_connect`,
174+
# so the Psycopg2Instrumentor is marked as instrumenting.
175175
_logger.warning(
176176
"Attempting to instrument Psycopg connection while already instrumented"
177177
)
178+
self._is_instrumented_by_opentelemetry = True
179+
return connection
180+
181+
# Save cursor_factory at instrumentor level because
182+
# psycopg2 connection type does not allow arbitrary attrs
183+
self._otel_cursor_factory = connection.cursor_factory
184+
connection.cursor_factory = _new_cursor_factory(
185+
base_factory=connection.cursor_factory,
186+
tracer_provider=tracer_provider,
187+
enable_commenter=enable_commenter,
188+
commenter_options=commenter_options,
189+
)
190+
self._is_instrumented_by_opentelemetry = True
191+
178192
return connection
179193

180194
# TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql
181-
@staticmethod
182-
def uninstrument_connection(connection):
183-
connection.cursor_factory = getattr(
184-
connection, _OTEL_CURSOR_FACTORY_KEY, None
185-
)
186-
195+
def uninstrument_connection(self, connection):
196+
self._is_instrumented_by_opentelemetry = False
197+
connection.cursor_factory = self._otel_cursor_factory
187198
return connection
188199

189200

@@ -231,14 +242,23 @@ def get_statement(self, cursor, args):
231242
return statement
232243

233244

234-
def _new_cursor_factory(db_api=None, base_factory=None, tracer_provider=None):
245+
def _new_cursor_factory(
246+
db_api: dbapi.DatabaseApiIntegration = None,
247+
base_factory: pg_cursor = None,
248+
tracer_provider: typing.Optional[trace_api.TracerProvider] = None,
249+
enable_commenter: bool = False,
250+
commenter_options: dict = None,
251+
):
235252
if not db_api:
236253
db_api = DatabaseApiIntegration(
237254
__name__,
238255
Psycopg2Instrumentor._DATABASE_SYSTEM,
239256
connection_attributes=Psycopg2Instrumentor._CONNECTION_ATTRIBUTES,
240257
version=__version__,
241258
tracer_provider=tracer_provider,
259+
enable_commenter=enable_commenter,
260+
commenter_options=commenter_options,
261+
connect_module=psycopg2,
242262
)
243263

244264
base_factory = base_factory or pg_cursor

0 commit comments

Comments
 (0)