@@ -64,6 +64,31 @@ def __iter__(self):
64
64
yield k [len (self .prefix ) :]
65
65
66
66
67
+ class _SpanRecorder (object ):
68
+ __slots__ = ("maxlen" , "finished_spans" , "open_span_count" )
69
+
70
+ def __init__ (self , maxlen ):
71
+ # type: (int) -> None
72
+ self .maxlen = maxlen
73
+ self .open_span_count = 0 # type: int
74
+ self .finished_spans = [] # type: List[Span]
75
+
76
+ def start_span (self , span ):
77
+ # type: (Span) -> None
78
+
79
+ # This is just so that we don't run out of memory while recording a lot
80
+ # of spans. At some point we just stop and flush out the start of the
81
+ # trace tree (i.e. the first n spans with the smallest
82
+ # start_timestamp).
83
+ self .open_span_count += 1
84
+ if self .open_span_count > self .maxlen :
85
+ span ._span_recorder = None
86
+
87
+ def finish_span (self , span ):
88
+ # type: (Span) -> None
89
+ self .finished_spans .append (span )
90
+
91
+
67
92
class Span (object ):
68
93
__slots__ = (
69
94
"trace_id" ,
@@ -78,7 +103,7 @@ class Span(object):
78
103
"timestamp" ,
79
104
"_tags" ,
80
105
"_data" ,
81
- "_finished_spans " ,
106
+ "_span_recorder " ,
82
107
"hub" ,
83
108
"_context_manager_state" ,
84
109
)
@@ -107,16 +132,18 @@ def __init__(
107
132
self .hub = hub
108
133
self ._tags = {} # type: Dict[str, str]
109
134
self ._data = {} # type: Dict[str, Any]
110
- self ._finished_spans = None # type: Optional[List[Span]]
111
135
self .start_timestamp = datetime .now ()
112
136
113
137
#: End timestamp of span
114
138
self .timestamp = None # type: Optional[datetime]
115
139
116
- def init_finished_spans (self ):
117
- # type: () -> None
118
- if self ._finished_spans is None :
119
- self ._finished_spans = []
140
+ self ._span_recorder = None # type: Optional[_SpanRecorder]
141
+
142
+ def init_finished_spans (self , maxlen ):
143
+ # type: (int) -> None
144
+ if self ._span_recorder is None :
145
+ self ._span_recorder = _SpanRecorder (maxlen )
146
+ self ._span_recorder .start_span (self )
120
147
121
148
def __repr__ (self ):
122
149
# type: () -> str
@@ -162,7 +189,8 @@ def new_span(self, **kwargs):
162
189
sampled = self .sampled ,
163
190
** kwargs
164
191
)
165
- rv ._finished_spans = self ._finished_spans
192
+
193
+ rv ._span_recorder = self ._span_recorder
166
194
return rv
167
195
168
196
@classmethod
@@ -252,11 +280,13 @@ def finish(self, hub=None):
252
280
253
281
self .timestamp = datetime .now ()
254
282
255
- if self ._finished_spans is not None :
256
- self ._finished_spans .append (self )
257
-
258
283
_maybe_create_breadcrumbs_from_span (hub , self )
259
284
285
+ if self ._span_recorder is None :
286
+ return None
287
+
288
+ self ._span_recorder .finish_span (self )
289
+
260
290
if self .transaction is None :
261
291
# If this has no transaction set we assume there's a parent
262
292
# transaction for this span that would be flushed out eventually.
@@ -285,7 +315,9 @@ def finish(self, hub=None):
285
315
"timestamp" : self .timestamp ,
286
316
"start_timestamp" : self .start_timestamp ,
287
317
"spans" : [
288
- s .to_json () for s in (self ._finished_spans or ()) if s is not self
318
+ s .to_json ()
319
+ for s in self ._span_recorder .finished_spans
320
+ if s is not self
289
321
],
290
322
}
291
323
)
@@ -354,11 +386,19 @@ def record_sql_queries(
354
386
executemany , # type: bool
355
387
):
356
388
# type: (...) -> Generator[Span, None, None]
357
- if not params_list or params_list == [None ]:
358
- params_list = None
359
389
360
- if paramstyle == "pyformat" :
361
- paramstyle = "format"
390
+ # TODO: Bring back capturing of params by default
391
+ if hub .client and hub .client .options ["_experiments" ].get (
392
+ "record_sql_params" , False
393
+ ):
394
+ if not params_list or params_list == [None ]:
395
+ params_list = None
396
+
397
+ if paramstyle == "pyformat" :
398
+ paramstyle = "format"
399
+ else :
400
+ params_list = None
401
+ paramstyle = None
362
402
363
403
query = _format_sql (cursor , query )
364
404
0 commit comments