Skip to content

Commit e7b07dc

Browse files
authored
[dbapi2] disable fetchone/fetchmany/fetchall tracing by default (#780)
* [dbapi2] allow disabling commit/rollback/fetch* tracing * [dbapi2] Use subclass for tracing fetch* methods * change configuration name * [dbapi2] update tests * remove unused imports * Fix sqlite3 tests * fix psycopg2 tests * fix mysqldb tests * fix more mysql tests * fix flake8 issue * fix pymysql tests * fix django tests * Allow enabling fetch* tracing from env variable
1 parent 8e679bd commit e7b07dc

File tree

13 files changed

+965
-429
lines changed

13 files changed

+965
-429
lines changed

ddtrace/contrib/dbapi/__init__.py

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88

99
from ddtrace import Pin
1010
from ddtrace.ext import AppTypes, sql
11+
from ddtrace.settings import config
12+
from ddtrace.utils.formats import asbool, get_env
1113

1214
log = logging.getLogger(__name__)
1315

16+
config._add('dbapi2', dict(
17+
trace_fetch_methods=asbool(get_env('dbapi2', 'trace_fetch_methods', 'false')),
18+
))
19+
1420

1521
class TracedCursor(wrapt.ObjectProxy):
1622
""" TracedCursor wraps a psql cursor and traces it's queries. """
@@ -72,6 +78,27 @@ def execute(self, query, *args, **kwargs):
7278
self._trace_method(self.__wrapped__.execute, self._self_datadog_name, query, {}, query, *args, **kwargs)
7379
return self
7480

81+
def callproc(self, proc, args):
82+
""" Wraps the cursor.callproc method"""
83+
self._self_last_execute_operation = proc
84+
return self._trace_method(self.__wrapped__.callproc, self._self_datadog_name, proc, {}, proc, args)
85+
86+
def __enter__(self):
87+
# previous versions of the dbapi didn't support context managers. let's
88+
# reference the func that would be called to ensure that errors
89+
# messages will be the same.
90+
self.__wrapped__.__enter__
91+
92+
# and finally, yield the traced cursor.
93+
return self
94+
95+
96+
class FetchTracedCursor(TracedCursor):
97+
"""
98+
Sub-class of :class:`TracedCursor` that also instruments `fetchone`, `fetchall`, and `fetchmany` methods.
99+
100+
We do not trace these functions by default since they can get very noisy (e.g. `fetchone` with 100k rows).
101+
"""
75102
def fetchone(self, *args, **kwargs):
76103
""" Wraps the cursor.fetchone method"""
77104
span_name = '{}.{}'.format(self._self_datadog_name, 'fetchone')
@@ -101,25 +128,18 @@ def fetchmany(self, *args, **kwargs):
101128
return self._trace_method(self.__wrapped__.fetchmany, span_name, self._self_last_execute_operation, extra_tags,
102129
*args, **kwargs)
103130

104-
def callproc(self, proc, args):
105-
""" Wraps the cursor.callproc method"""
106-
self._self_last_execute_operation = proc
107-
return self._trace_method(self.__wrapped__.callproc, self._self_datadog_name, proc, {}, proc, args)
108-
109-
def __enter__(self):
110-
# previous versions of the dbapi didn't support context managers. let's
111-
# reference the func that would be called to ensure that errors
112-
# messages will be the same.
113-
self.__wrapped__.__enter__
114-
115-
# and finally, yield the traced cursor.
116-
return self
117-
118131

119132
class TracedConnection(wrapt.ObjectProxy):
120133
""" TracedConnection wraps a Connection with tracing code. """
121134

122-
def __init__(self, conn, pin=None, cursor_cls=TracedCursor):
135+
def __init__(self, conn, pin=None, cursor_cls=None):
136+
# Set default cursor class if one was not provided
137+
if not cursor_cls:
138+
# Do not trace `fetch*` methods by default
139+
cursor_cls = TracedCursor
140+
if config.dbapi2.trace_fetch_methods:
141+
cursor_cls = FetchTracedCursor
142+
123143
super(TracedConnection, self).__init__(conn)
124144
name = _get_vendor(conn)
125145
self._self_datadog_name = '{}.connection'.format(name)

ddtrace/contrib/psycopg/patch.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import wrapt
44

55
# project
6-
from ddtrace import Pin
6+
from ddtrace import Pin, config
77
from ddtrace.contrib import dbapi
88
from ddtrace.ext import sql, net, db
99

@@ -51,14 +51,21 @@ def _trace_method(self, method, name, resource, extra_tags, *args, **kwargs):
5151
return super(Psycopg2TracedCursor, self)._trace_method(method, name, resource, extra_tags, *args, **kwargs)
5252

5353

54+
class Psycopg2FetchTracedCursor(Psycopg2TracedCursor, dbapi.FetchTracedCursor):
55+
""" FetchTracedCursor for psycopg2 """
56+
57+
5458
class Psycopg2TracedConnection(dbapi.TracedConnection):
5559
""" TracedConnection wraps a Connection with tracing code. """
5660

57-
def __init__(self, conn, pin=None, cursor_cls=Psycopg2TracedCursor):
58-
super(Psycopg2TracedConnection, self).__init__(conn, pin)
59-
# wrapt requires prefix of `_self` for attributes that are only in the
60-
# proxy (since some of our source objects will use `__slots__`)
61-
self._self_cursor_cls = cursor_cls
61+
def __init__(self, conn, pin=None, cursor_cls=None):
62+
if not cursor_cls:
63+
# Do not trace `fetch*` methods by default
64+
cursor_cls = Psycopg2TracedCursor
65+
if config.dbapi2.trace_fetch_methods:
66+
cursor_cls = Psycopg2FetchTracedCursor
67+
68+
super(Psycopg2TracedConnection, self).__init__(conn, pin, cursor_cls=cursor_cls)
6269

6370

6471
def patch_conn(conn, traced_conn_cls=Psycopg2TracedConnection):

0 commit comments

Comments
 (0)