Skip to content

Commit 78c948b

Browse files
gregoiredxxrmx
andauthored
feat: add support for capture_parameters to Psycopg2Instrumentor (#4212)
* feat: add support for capture_parameters to Psycopg2Instrumentor * Update CHANGELOG.md --------- Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
1 parent 97bd32d commit 78c948b

4 files changed

Lines changed: 84 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
([#4289](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4289))
1818
- `opentelemetry-instrumentation`: Add support for wrapt 2.x
1919
([#4203](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4203))
20+
- `opentelemetry-instrumentation-psycopg2`: Add parameter `capture_parameters` to instrumentor.
21+
([#4212](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4212))
2022

2123
### Fixed
2224

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@
136136
Warning:
137137
Capture of sqlcomment in ``db.statement`` may have high cardinality without platform normalization. See `Semantic Conventions for database spans <https://opentelemetry.io/docs/specs/semconv/database/database-spans/#generating-a-summary-of-the-query-text>`_ for more information.
138138
139+
Capture parameters
140+
******************
141+
By default, only statements are captured, without the associated query parameters.
142+
To capture query parameters in the span attribute `db.statement.parameters`, enable `capture_parameters`.
143+
144+
.. code:: python
145+
146+
from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor
147+
148+
Psycopg2Instrumentor().instrument(
149+
capture_parameters=True,
150+
)
151+
139152
API
140153
---
141154
"""
@@ -213,6 +226,7 @@ def _instrument(self, **kwargs):
213226
enable_attribute_commenter = kwargs.get(
214227
"enable_attribute_commenter", False
215228
)
229+
capture_parameters = kwargs.get("capture_parameters", False)
216230
dbapi.wrap_connect(
217231
__name__,
218232
psycopg2,
@@ -225,6 +239,7 @@ def _instrument(self, **kwargs):
225239
enable_commenter=enable_sqlcommenter,
226240
commenter_options=commenter_options,
227241
enable_attribute_commenter=enable_attribute_commenter,
242+
capture_parameters=capture_parameters,
228243
)
229244

230245
def _uninstrument(self, **kwargs):

instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_instrumentation.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,21 @@
1515
from unittest import TestCase
1616
from unittest.mock import Mock, call, patch
1717

18+
import psycopg2
19+
1820
from opentelemetry.instrumentation.auto_instrumentation._load import (
1921
_load_instrumentors,
2022
)
21-
from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor
23+
from opentelemetry.instrumentation.psycopg2 import (
24+
DatabaseApiIntegration,
25+
Psycopg2Instrumentor,
26+
)
2227
from opentelemetry.instrumentation.psycopg2.package import (
2328
_instruments_psycopg2,
2429
_instruments_psycopg2_binary,
2530
)
31+
from opentelemetry.instrumentation.psycopg2.version import __version__
32+
from opentelemetry.test.test_base import TestBase
2633

2734

2835
class TestPsycopg2InstrumentationDependencies(TestCase):
@@ -160,3 +167,41 @@ def _instrumentation_loaded_successfully_call():
160167
mock_logger.debug.assert_has_calls(
161168
[_instrumentation_loaded_successfully_call()]
162169
)
170+
171+
172+
@patch("opentelemetry.instrumentation.psycopg2.dbapi")
173+
class TestPsycopg2InstrumentorParameters(TestBase):
174+
def tearDown(self):
175+
super().tearDown()
176+
with self.disable_logging():
177+
Psycopg2Instrumentor().uninstrument()
178+
179+
def test_instrument_defaults(self, mock_dbapi): # pylint: disable=no-self-use
180+
Psycopg2Instrumentor().instrument()
181+
182+
mock_dbapi.wrap_connect.assert_called_once_with(
183+
"opentelemetry.instrumentation.psycopg2",
184+
psycopg2,
185+
"connect",
186+
"postgresql",
187+
{
188+
"database": "info.dbname",
189+
"port": "info.port",
190+
"host": "info.host",
191+
"user": "info.user",
192+
},
193+
version=__version__,
194+
tracer_provider=None,
195+
db_api_integration_factory=DatabaseApiIntegration,
196+
enable_commenter=False,
197+
commenter_options={},
198+
enable_attribute_commenter=False,
199+
capture_parameters=False,
200+
)
201+
202+
def test_instrument_capture_parameters(self, mock_dbapi):
203+
Psycopg2Instrumentor().instrument(capture_parameters=True)
204+
205+
self.assertTrue(
206+
mock_dbapi.wrap_connect.call_args.kwargs["capture_parameters"]
207+
)

instrumentation/opentelemetry-instrumentation-psycopg2/tests/test_psycopg2_integration.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,24 @@ def test_no_op_tracer_provider(self):
371371
cursor.execute(query)
372372
spans_list = self.memory_exporter.get_finished_spans()
373373
self.assertEqual(len(spans_list), 0)
374+
375+
def test_span_capture_params_deactivated_by_default(self):
376+
Psycopg2Instrumentor().instrument()
377+
cnx = psycopg2.connect(database="test")
378+
cursor = cnx.cursor()
379+
query = "SELECT * FROM test WHERE id = %s AND name = %s"
380+
cursor.execute(query, (42, "John Doe"))
381+
spans_list = self.memory_exporter.get_finished_spans()
382+
self.assertNotIn("db.statement.parameters", spans_list[0].attributes)
383+
384+
def test_span_capture_params_activated(self):
385+
Psycopg2Instrumentor().instrument(capture_parameters=True)
386+
cnx = psycopg2.connect(database="test")
387+
cursor = cnx.cursor()
388+
query = "SELECT * FROM test WHERE id = %s AND name = %s"
389+
cursor.execute(query, (42, "John Doe"))
390+
spans_list = self.memory_exporter.get_finished_spans()
391+
self.assertEqual(
392+
spans_list[0].attributes["db.statement.parameters"],
393+
"(42, 'John Doe')",
394+
)

0 commit comments

Comments
 (0)