Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
69d1ea3
Fix psycopg2 instrument_connection
tammy-baylis-swi Nov 23, 2024
c6181ef
Changelog
tammy-baylis-swi Nov 23, 2024
72d41e5
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 4, 2024
ea8d73d
Fix unit test
tammy-baylis-swi Dec 5, 2024
a0f74ca
Rm psycopg2 wrapt dep
tammy-baylis-swi Dec 5, 2024
a0c9940
Fix docs and comments
tammy-baylis-swi Dec 5, 2024
b591b0a
Add and update tests
tammy-baylis-swi Dec 5, 2024
59fa855
Rm enable_commenter fixes for a different pr
tammy-baylis-swi Dec 5, 2024
dd7e3ea
Revert doc reqs
tammy-baylis-swi Dec 5, 2024
0b3f273
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 5, 2024
40f077b
Update readme
tammy-baylis-swi Dec 6, 2024
5a099d5
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 9, 2024
a7f969d
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 11, 2024
0f7baec
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 19, 2024
a2fa981
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Dec 20, 2024
e8d47bf
Rm instrument_connection is-instrumented check; use dict to store cnx
tammy-baylis-swi Dec 21, 2024
8a316a4
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 2, 2025
b3b3888
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 7, 2025
238746e
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 8, 2025
6f67b33
Rm cursor_factory restore at uninstrument_connection
tammy-baylis-swi Jan 10, 2025
b2edf01
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 10, 2025
86dd604
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 13, 2025
9ef7b50
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 14, 2025
7f3632a
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 15, 2025
38b9d09
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Feb 27, 2025
680b0f5
Changelog
tammy-baylis-swi Feb 27, 2025
6eff789
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi May 1, 2025
0102cee
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Jan 15, 2026
b6a3af2
Changelog
tammy-baylis-swi Jan 15, 2026
b065a38
Fix docstring
tammy-baylis-swi Jan 15, 2026
8abf974
Merge branch 'main' into fix-psycopg2-instrument-connection
tammy-baylis-swi Feb 19, 2026
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4078](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4171))
- `opentelemetry-instrumentation-aiohttp-server`: fix HTTP error inconsistencies
([#4175](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4175))
- `opentelemetry-instrumentation-psycopg2`: fix AttributeError at `instrument_connection`
([#3043](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3043))

### Breaking changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
)
from psycopg2.sql import Composed # pylint: disable=no-name-in-module

from opentelemetry import trace as trace_api
from opentelemetry.instrumentation import dbapi
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.psycopg2.package import (
Expand All @@ -161,7 +162,6 @@
from opentelemetry.instrumentation.psycopg2.version import __version__

_logger = logging.getLogger(__name__)
_OTEL_CURSOR_FACTORY_KEY = "_otel_orig_cursor_factory"


class Psycopg2Instrumentor(BaseInstrumentor):
Expand Down Expand Up @@ -193,8 +193,8 @@ def instrumentation_dependencies(self) -> Collection[str]:
return _instruments_any

def _instrument(self, **kwargs):
"""Integrate with PostgreSQL Psycopg library.
Psycopg: http://initd.org/psycopg/
"""Integrate with PostgreSQL Psycopg2 library.
Psycopg2: https://www.psycopg.org/docs/
"""
tracer_provider = kwargs.get("tracer_provider")
enable_sqlcommenter = kwargs.get("enable_commenter", False)
Expand Down Expand Up @@ -222,7 +222,10 @@ 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):
def instrument_connection(
connection,
tracer_provider: typing.Optional[trace_api.TracerProvider] = None,
):
"""Enable instrumentation in a psycopg2 connection.

Args:
Expand All @@ -235,31 +238,19 @@ def instrument_connection(connection, tracer_provider=None):
Returns:
An instrumented psycopg2 connection object.
"""

if not hasattr(connection, "_is_instrumented_by_opentelemetry"):
Comment thread
tammy-baylis-swi marked this conversation as resolved.
connection._is_instrumented_by_opentelemetry = False

if not connection._is_instrumented_by_opentelemetry:
setattr(
connection, _OTEL_CURSOR_FACTORY_KEY, connection.cursor_factory
)
connection.cursor_factory = _new_cursor_factory(
tracer_provider=tracer_provider
)
connection._is_instrumented_by_opentelemetry = True
else:
_logger.warning(
"Attempting to instrument Psycopg connection while already instrumented"
)
# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
connection.cursor_factory = _new_cursor_factory(
base_factory=connection.cursor_factory,
tracer_provider=tracer_provider,
)
return connection

# TODO(owais): check if core dbapi can do this for all dbapi implementations e.g, pymysql and mysql
@staticmethod
def uninstrument_connection(connection):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should leave this as a no-op.

If we used a class-level store (eg WeakKeyDictionary), we could track the factories using connection ID and then uninstrument_connection could work.

What do you think @tammy-baylis-swi?

connection.cursor_factory = getattr(
connection, _OTEL_CURSOR_FACTORY_KEY, None
)

# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
return connection


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import opentelemetry.instrumentation.psycopg2
from opentelemetry import trace
from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor
from opentelemetry.instrumentation.psycopg2 import (
Psycopg2Instrumentor,
)
from opentelemetry.sdk import resources
from opentelemetry.test.test_base import TestBase

Expand Down Expand Up @@ -190,7 +192,8 @@ def test_instrument_connection(self):
spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 0)

cnx = Psycopg2Instrumentor().instrument_connection(cnx)
instrumentor = Psycopg2Instrumentor()
cnx = instrumentor.instrument_connection(cnx)
cursor = cnx.cursor()
cursor.execute(query)

Expand All @@ -207,17 +210,49 @@ def test_instrument_connection_with_instrument(self):
spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 0)

Psycopg2Instrumentor().instrument()
instrumentor = Psycopg2Instrumentor()
instrumentor.instrument()

cnx = psycopg2.connect(database="test")
Comment thread
tammy-baylis-swi marked this conversation as resolved.
cnx = Psycopg2Instrumentor().instrument_connection(cnx)

cursor = cnx.cursor()
cursor.execute(query)

spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
# self.assertEqual(len(spans_list), 1)
self.assertEqual(len(spans_list), 2)

def test_instrument_connection_with_instrument_connection(self):
cnx = psycopg2.connect(database="test")
query = "SELECT * FROM test"
cursor = cnx.cursor()
cursor.execute(query)

spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 0)

cnx = psycopg2.connect(database="test")
instrumentor = Psycopg2Instrumentor()
cnx = instrumentor.instrument_connection(cnx)

instrumentor = Psycopg2Instrumentor()
cnx = instrumentor.instrument_connection(cnx)
cursor = cnx.cursor()
cursor.execute(query)

spans_list = self.memory_exporter.get_finished_spans()
# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
# self.assertEqual(len(spans_list), 1)
self.assertEqual(len(spans_list), 2)

# pylint: disable=unused-argument
def test_uninstrument_connection_with_instrument(self):
Psycopg2Instrumentor().instrument()
instrumentor = Psycopg2Instrumentor()
instrumentor.instrument()
cnx = psycopg2.connect(database="test")
query = "SELECT * FROM test"
cursor = cnx.cursor()
Expand All @@ -230,13 +265,16 @@ def test_uninstrument_connection_with_instrument(self):
cursor = cnx.cursor()
cursor.execute(query)

spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
# spans_list = self.memory_exporter.get_finished_spans()
# self.assertEqual(len(spans_list), 1)

# pylint: disable=unused-argument
def test_uninstrument_connection_with_instrument_connection(self):
cnx = psycopg2.connect(database="test")
Psycopg2Instrumentor().instrument_connection(cnx)
instrumentor = Psycopg2Instrumentor()
instrumentor.instrument_connection(cnx)
query = "SELECT * FROM test"
cursor = cnx.cursor()
cursor.execute(query)
Expand All @@ -248,8 +286,10 @@ def test_uninstrument_connection_with_instrument_connection(self):
cursor = cnx.cursor()
cursor.execute(query)

spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
# TODO Add check for attempt to instrument a connection when already instrumented
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3138
# spans_list = self.memory_exporter.get_finished_spans()
# self.assertEqual(len(spans_list), 1)

@mock.patch("opentelemetry.instrumentation.dbapi.wrap_connect")
def test_sqlcommenter_enabled(self, event_mocked):
Expand Down