@@ -63,7 +63,7 @@ def hello():
63
63
from opentelemetry .propagate import extract
64
64
from opentelemetry .semconv .trace import SpanAttributes
65
65
from opentelemetry .util ._time import _time_ns
66
- from opentelemetry .util .http import get_excluded_urls
66
+ from opentelemetry .util .http import get_excluded_urls , parse_excluded_urls
67
67
68
68
_logger = getLogger (__name__ )
69
69
@@ -73,7 +73,7 @@ def hello():
73
73
_ENVIRON_TOKEN = "opentelemetry-flask.token"
74
74
75
75
76
- _excluded_urls = get_excluded_urls ("FLASK" )
76
+ _excluded_urls_from_env = get_excluded_urls ("FLASK" )
77
77
78
78
79
79
def get_default_span_name ():
@@ -85,7 +85,7 @@ def get_default_span_name():
85
85
return span_name
86
86
87
87
88
- def _rewrapped_app (wsgi_app , response_hook = None ):
88
+ def _rewrapped_app (wsgi_app , response_hook = None , excluded_urls = None ):
89
89
def _wrapped_app (wrapped_app_environ , start_response ):
90
90
# We want to measure the time for route matching, etc.
91
91
# In theory, we could start the span here and use
@@ -94,7 +94,9 @@ def _wrapped_app(wrapped_app_environ, start_response):
94
94
wrapped_app_environ [_ENVIRON_STARTTIME_KEY ] = _time_ns ()
95
95
96
96
def _start_response (status , response_headers , * args , ** kwargs ):
97
- if not _excluded_urls .url_disabled (flask .request .url ):
97
+ if excluded_urls is None or not excluded_urls .url_disabled (
98
+ flask .request .url
99
+ ):
98
100
span = flask .request .environ .get (_ENVIRON_SPAN_KEY )
99
101
100
102
propagator = get_global_response_propagator ()
@@ -123,9 +125,11 @@ def _start_response(status, response_headers, *args, **kwargs):
123
125
return _wrapped_app
124
126
125
127
126
- def _wrapped_before_request (request_hook = None , tracer = None ):
128
+ def _wrapped_before_request (
129
+ request_hook = None , tracer = None , excluded_urls = None
130
+ ):
127
131
def _before_request ():
128
- if _excluded_urls .url_disabled (flask .request .url ):
132
+ if excluded_urls and excluded_urls .url_disabled (flask .request .url ):
129
133
return
130
134
flask_request_environ = flask .request .environ
131
135
span_name = get_default_span_name ()
@@ -163,29 +167,33 @@ def _before_request():
163
167
return _before_request
164
168
165
169
166
- def _teardown_request (exc ):
167
- # pylint: disable=E1101
168
- if _excluded_urls .url_disabled (flask .request .url ):
169
- return
170
+ def _wrapped_teardown_request (excluded_urls = None ):
171
+ def _teardown_request (exc ):
172
+ # pylint: disable=E1101
173
+ if excluded_urls and excluded_urls .url_disabled (flask .request .url ):
174
+ return
170
175
171
- activation = flask .request .environ .get (_ENVIRON_ACTIVATION_KEY )
172
- if not activation :
173
- # This request didn't start a span, maybe because it was created in a
174
- # way that doesn't run `before_request`, like when it is created with
175
- # `app.test_request_context`.
176
- return
176
+ activation = flask .request .environ .get (_ENVIRON_ACTIVATION_KEY )
177
+ if not activation :
178
+ # This request didn't start a span, maybe because it was created in
179
+ # a way that doesn't run `before_request`, like when it is created
180
+ # with `app.test_request_context`.
181
+ return
177
182
178
- if exc is None :
179
- activation .__exit__ (None , None , None )
180
- else :
181
- activation .__exit__ (
182
- type (exc ), exc , getattr (exc , "__traceback__" , None )
183
- )
184
- context .detach (flask .request .environ .get (_ENVIRON_TOKEN ))
183
+ if exc is None :
184
+ activation .__exit__ (None , None , None )
185
+ else :
186
+ activation .__exit__ (
187
+ type (exc ), exc , getattr (exc , "__traceback__" , None )
188
+ )
189
+ context .detach (flask .request .environ .get (_ENVIRON_TOKEN ))
190
+
191
+ return _teardown_request
185
192
186
193
187
194
class _InstrumentedFlask (flask .Flask ):
188
195
196
+ _excluded_urls = None
189
197
_tracer_provider = None
190
198
_request_hook = None
191
199
_response_hook = None
@@ -197,18 +205,26 @@ def __init__(self, *args, **kwargs):
197
205
self ._is_instrumented_by_opentelemetry = True
198
206
199
207
self .wsgi_app = _rewrapped_app (
200
- self .wsgi_app , _InstrumentedFlask ._response_hook
208
+ self .wsgi_app ,
209
+ _InstrumentedFlask ._response_hook ,
210
+ excluded_urls = _InstrumentedFlask ._excluded_urls ,
201
211
)
202
212
203
213
tracer = trace .get_tracer (
204
214
__name__ , __version__ , _InstrumentedFlask ._tracer_provider
205
215
)
206
216
207
217
_before_request = _wrapped_before_request (
208
- _InstrumentedFlask ._request_hook , tracer ,
218
+ _InstrumentedFlask ._request_hook ,
219
+ tracer ,
220
+ excluded_urls = _InstrumentedFlask ._excluded_urls ,
209
221
)
210
222
self ._before_request = _before_request
211
223
self .before_request (_before_request )
224
+
225
+ _teardown_request = _wrapped_teardown_request (
226
+ excluded_urls = _InstrumentedFlask ._excluded_urls ,
227
+ )
212
228
self .teardown_request (_teardown_request )
213
229
214
230
@@ -232,27 +248,51 @@ def _instrument(self, **kwargs):
232
248
_InstrumentedFlask ._response_hook = response_hook
233
249
tracer_provider = kwargs .get ("tracer_provider" )
234
250
_InstrumentedFlask ._tracer_provider = tracer_provider
251
+ excluded_urls = kwargs .get ("excluded_urls" )
252
+ _InstrumentedFlask ._excluded_urls = (
253
+ _excluded_urls_from_env
254
+ if excluded_urls is None
255
+ else parse_excluded_urls (excluded_urls )
256
+ )
235
257
flask .Flask = _InstrumentedFlask
236
258
237
259
def _uninstrument (self , ** kwargs ):
238
260
flask .Flask = self ._original_flask
239
261
240
262
@staticmethod
241
263
def instrument_app (
242
- app , request_hook = None , response_hook = None , tracer_provider = None
264
+ app ,
265
+ request_hook = None ,
266
+ response_hook = None ,
267
+ tracer_provider = None ,
268
+ excluded_urls = None ,
243
269
):
244
270
if not hasattr (app , "_is_instrumented_by_opentelemetry" ):
245
271
app ._is_instrumented_by_opentelemetry = False
246
272
247
273
if not app ._is_instrumented_by_opentelemetry :
274
+ excluded_urls = (
275
+ parse_excluded_urls (excluded_urls )
276
+ if excluded_urls is not None
277
+ else _excluded_urls_from_env
278
+ )
248
279
app ._original_wsgi_app = app .wsgi_app
249
- app .wsgi_app = _rewrapped_app (app .wsgi_app , response_hook )
280
+ app .wsgi_app = _rewrapped_app (
281
+ app .wsgi_app , response_hook , excluded_urls = excluded_urls
282
+ )
250
283
251
284
tracer = trace .get_tracer (__name__ , __version__ , tracer_provider )
252
285
253
- _before_request = _wrapped_before_request (request_hook , tracer )
286
+ _before_request = _wrapped_before_request (
287
+ request_hook , tracer , excluded_urls = excluded_urls ,
288
+ )
254
289
app ._before_request = _before_request
255
290
app .before_request (_before_request )
291
+
292
+ _teardown_request = _wrapped_teardown_request (
293
+ excluded_urls = excluded_urls ,
294
+ )
295
+ app ._teardown_request = _teardown_request
256
296
app .teardown_request (_teardown_request )
257
297
app ._is_instrumented_by_opentelemetry = True
258
298
else :
@@ -267,7 +307,7 @@ def uninstrument_app(app):
267
307
268
308
# FIXME add support for other Flask blueprints that are not None
269
309
app .before_request_funcs [None ].remove (app ._before_request )
270
- app .teardown_request_funcs [None ].remove (_teardown_request )
310
+ app .teardown_request_funcs [None ].remove (app . _teardown_request )
271
311
del app ._original_wsgi_app
272
312
app ._is_instrumented_by_opentelemetry = False
273
313
else :
0 commit comments