@@ -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
@@ -209,6 +217,10 @@ def __init__(self, *args, **kwargs):
209
217
)
210
218
self ._before_request = _before_request
211
219
self .before_request (_before_request )
220
+
221
+ _teardown_request = _wrapped_teardown_request (
222
+ excluded_urls = _InstrumentedFlask ._excluded_urls ,
223
+ )
212
224
self .teardown_request (_teardown_request )
213
225
214
226
@@ -232,27 +244,49 @@ def _instrument(self, **kwargs):
232
244
_InstrumentedFlask ._response_hook = response_hook
233
245
tracer_provider = kwargs .get ("tracer_provider" )
234
246
_InstrumentedFlask ._tracer_provider = tracer_provider
247
+ excluded_urls = kwargs .get ("excluded_urls" )
248
+ _InstrumentedFlask ._excluded_urls = (
249
+ _excluded_urls_from_env
250
+ if excluded_urls is None
251
+ else parse_excluded_urls (excluded_urls )
252
+ )
235
253
flask .Flask = _InstrumentedFlask
236
254
237
255
def _uninstrument (self , ** kwargs ):
238
256
flask .Flask = self ._original_flask
239
257
240
258
@staticmethod
241
259
def instrument_app (
242
- app , request_hook = None , response_hook = None , tracer_provider = None
260
+ app ,
261
+ request_hook = None ,
262
+ response_hook = None ,
263
+ tracer_provider = None ,
264
+ excluded_urls = None ,
243
265
):
244
266
if not hasattr (app , "_is_instrumented_by_opentelemetry" ):
245
267
app ._is_instrumented_by_opentelemetry = False
246
268
247
269
if not app ._is_instrumented_by_opentelemetry :
270
+ excluded_urls = (
271
+ parse_excluded_urls (excluded_urls )
272
+ if excluded_urls is not None
273
+ else _excluded_urls_from_env
274
+ )
248
275
app ._original_wsgi_app = app .wsgi_app
249
276
app .wsgi_app = _rewrapped_app (app .wsgi_app , response_hook )
250
277
251
278
tracer = trace .get_tracer (__name__ , __version__ , tracer_provider )
252
279
253
- _before_request = _wrapped_before_request (request_hook , tracer )
280
+ _before_request = _wrapped_before_request (
281
+ request_hook , tracer , excluded_urls = excluded_urls ,
282
+ )
254
283
app ._before_request = _before_request
255
284
app .before_request (_before_request )
285
+
286
+ _teardown_request = _wrapped_teardown_request (
287
+ excluded_urls = excluded_urls ,
288
+ )
289
+ app ._teardown_request = _teardown_request
256
290
app .teardown_request (_teardown_request )
257
291
app ._is_instrumented_by_opentelemetry = True
258
292
else :
@@ -267,7 +301,7 @@ def uninstrument_app(app):
267
301
268
302
# FIXME add support for other Flask blueprints that are not None
269
303
app .before_request_funcs [None ].remove (app ._before_request )
270
- app .teardown_request_funcs [None ].remove (_teardown_request )
304
+ app .teardown_request_funcs [None ].remove (app . _teardown_request )
271
305
del app ._original_wsgi_app
272
306
app ._is_instrumented_by_opentelemetry = False
273
307
else :
0 commit comments