Skip to content

Commit 9defd95

Browse files
ashu658ItayGibel-helios
authored andcommitted
Conditionally create server spans for flask (open-telemetry#828)
* Making span as internal in presence of a span in current context * Updating changelog * Removing extra print statements * Resolving comments: Setting current context as parent in its presence * Ignoring pylint check as django.conf.urls.url is removed in django 4.0 Django release notes: https://docs.djangoproject.com/en/4.0/releases/4.0/ * Removing changes in django files
1 parent b084a9b commit 9defd95

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
- `opentelemetry-instrumentation-tornado` Add support instrumentation for Tornado 5.1.1
2424
([#812](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/812))
25+
26+
- `opentelemetry-instrumentation-flask` Flask: Conditionally create SERVER spans
27+
([#828](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/828))
2528

2629
- `opentelemetry-instrumentation-kafka-python` added kafka-python module instrumentation.
2730
([#814](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/814))

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

+16-5
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,24 @@ def _before_request():
176176
return
177177
flask_request_environ = flask.request.environ
178178
span_name = get_default_span_name()
179-
token = context.attach(
180-
extract(flask_request_environ, getter=otel_wsgi.wsgi_getter)
181-
)
179+
180+
token = ctx = span_kind = None
181+
182+
if trace.get_current_span() is trace.INVALID_SPAN:
183+
ctx = extract(flask_request_environ, getter=otel_wsgi.wsgi_getter)
184+
token = context.attach(ctx)
185+
span_kind = trace.SpanKind.SERVER
186+
else:
187+
ctx = context.get_current()
188+
span_kind = trace.SpanKind.INTERNAL
182189

183190
span = tracer.start_span(
184191
span_name,
185-
kind=trace.SpanKind.SERVER,
192+
ctx,
193+
kind=span_kind,
186194
start_time=flask_request_environ.get(_ENVIRON_STARTTIME_KEY),
187195
)
196+
188197
if request_hook:
189198
request_hook(span, flask_request_environ)
190199

@@ -229,7 +238,9 @@ def _teardown_request(exc):
229238
activation.__exit__(
230239
type(exc), exc, getattr(exc, "__traceback__", None)
231240
)
232-
context.detach(flask.request.environ.get(_ENVIRON_TOKEN))
241+
242+
if flask.request.environ.get(_ENVIRON_TOKEN, None):
243+
context.detach(flask.request.environ.get(_ENVIRON_TOKEN))
233244

234245
return _teardown_request
235246

instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py

+29
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
get_global_response_propagator,
2424
set_global_response_propagator,
2525
)
26+
from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware
2627
from opentelemetry.sdk.resources import Resource
2728
from opentelemetry.semconv.trace import SpanAttributes
2829
from opentelemetry.test.test_base import TestBase
@@ -413,3 +414,31 @@ def test_custom_span_name(self):
413414
span_list[0].resource.attributes["service.name"],
414415
"flask-api-no-app",
415416
)
417+
418+
419+
class TestProgrammaticWrappedWithOtherFramework(
420+
InstrumentationTest, TestBase, WsgiTestBase
421+
):
422+
def setUp(self):
423+
super().setUp()
424+
425+
self.app = Flask(__name__)
426+
self.app.wsgi_app = OpenTelemetryMiddleware(self.app.wsgi_app)
427+
FlaskInstrumentor().instrument_app(self.app)
428+
self._common_initialization()
429+
430+
def tearDown(self) -> None:
431+
super().tearDown()
432+
with self.disable_logging():
433+
FlaskInstrumentor().uninstrument_app(self.app)
434+
435+
def test_mark_span_internal_in_presence_of_span_from_other_framework(self):
436+
resp = self.client.get("/hello/123")
437+
self.assertEqual(200, resp.status_code)
438+
resp.get_data()
439+
span_list = self.memory_exporter.get_finished_spans()
440+
self.assertEqual(trace.SpanKind.INTERNAL, span_list[0].kind)
441+
self.assertEqual(trace.SpanKind.SERVER, span_list[1].kind)
442+
self.assertEqual(
443+
span_list[0].parent.span_id, span_list[1].context.span_id
444+
)

0 commit comments

Comments
 (0)