diff --git a/examples/tracing/templates/index.html b/examples/tracing/templates/index.html index 2aa95e789c..c4d8f06c51 100644 --- a/examples/tracing/templates/index.html +++ b/examples/tracing/templates/index.html @@ -1,4 +1,6 @@ - + + +{{ sentry_trace }} @@ -14,14 +16,6 @@ debug: true }); -window.setTimeout(function() { - const scope = Sentry.getCurrentHub().getScope(); - // TODO: Wait for Daniel's traceparent API - scope.setSpan(scope.getSpan().constructor.fromTraceparent( - "00-{{ traceparent['sentry-trace'].strip("-") }}-00" - )); -}); - async function compute() { const res = await fetch( "/compute/" + diff --git a/sentry_sdk/integrations/flask.py b/sentry_sdk/integrations/flask.py index e4008fcdbe..8883cbb724 100644 --- a/sentry_sdk/integrations/flask.py +++ b/sentry_sdk/integrations/flask.py @@ -27,6 +27,7 @@ try: from flask import ( # type: ignore + Markup, Request, Flask, _request_ctx_stack, @@ -34,6 +35,7 @@ __version__ as FLASK_VERSION, ) from flask.signals import ( + before_render_template, got_request_exception, request_started, ) @@ -77,6 +79,7 @@ def setup_once(): if version < (0, 10): raise DidNotEnable("Flask 0.10 or newer is required.") + before_render_template.connect(_add_sentry_trace) request_started.connect(_request_started) got_request_exception.connect(_capture_exception) @@ -94,6 +97,23 @@ def sentry_patched_wsgi_app(self, environ, start_response): Flask.__call__ = sentry_patched_wsgi_app # type: ignore +def _add_sentry_trace(sender, template, context, **extra): + # type: (Flask, Any, Dict[str, Any], **Any) -> None + + if "sentry_trace" in context: + return + + sentry_span = Hub.current.scope.span + context["sentry_trace"] = ( + Markup( + '' + % (sentry_span.to_traceparent(),) + ) + if sentry_span + else "" + ) + + def _request_started(sender, **kwargs): # type: (Flask, **Any) -> None hub = Hub.current diff --git a/tests/integrations/flask/test_flask.py b/tests/integrations/flask/test_flask.py index 6c173e223d..8723a35c86 100644 --- a/tests/integrations/flask/test_flask.py +++ b/tests/integrations/flask/test_flask.py @@ -6,7 +6,14 @@ flask = pytest.importorskip("flask") -from flask import Flask, Response, request, abort, stream_with_context +from flask import ( + Flask, + Response, + request, + abort, + stream_with_context, + render_template_string, +) from flask.views import View from flask_login import LoginManager, login_user @@ -365,7 +372,7 @@ def index(): assert transaction_event["request"]["data"] == data -@pytest.mark.parametrize("input_char", [u"a", b"a"]) +@pytest.mark.parametrize("input_char", ["a", b"a"]) def test_flask_too_large_raw_request(sentry_init, input_char, capture_events, app): sentry_init(integrations=[flask_sentry.FlaskIntegration()], request_bodies="small") @@ -737,3 +744,34 @@ def dispatch_request(self): assert event["message"] == "hi" assert event["transaction"] == "hello_class" + + +def test_sentry_trace_context(sentry_init, app, capture_events): + sentry_init(integrations=[flask_sentry.FlaskIntegration()]) + events = capture_events() + + @app.route("/") + def index(): + sentry_span = Hub.current.scope.span + capture_message(sentry_span.to_traceparent()) + return render_template_string("{{ sentry_trace }}") + + with app.test_client() as client: + response = client.get("/") + assert response.status_code == 200 + assert response.data.decode( + "utf-8" + ) == '' % (events[0]["message"],) + + +def test_dont_override_sentry_trace_context(sentry_init, app): + sentry_init(integrations=[flask_sentry.FlaskIntegration()]) + + @app.route("/") + def index(): + return render_template_string("{{ sentry_trace }}", sentry_trace="hi") + + with app.test_client() as client: + response = client.get("/") + assert response.status_code == 200 + assert response.data == b"hi"