sentry-python
sentry-python copied to clipboard
Performance Monitoring doesn't work with Werkzeug DebuggedApplication
How do you use Sentry?
Sentry Saas (sentry.io)
Version
1.5.10
Steps to Reproduce
- Use Flask Integration
- Enable Werkzeug's
DebugApplication
mode - Set the
SENTRY_DSN
environment variable - Run web server
- Execute a GET request to any endpoint
Minimal example code:
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from werkzeug.debug import DebuggedApplication
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
SENTRY_ENVIRONMENT = os.getenv("SENTRY_ENVIRONMENT", "dev")
SENTRY_SAMPLE_RATE = float(os.getenv("SENTRY_SAMPLE_RATE", "0.8"))
SENTRY_TRACE_SAMPLE_RATE = float(os.getenv("SENTRY_TRACE_SAMPLE_RATE", "0.8"))
integrations = [FlaskIntegration(transaction_style="url"), SqlalchemyIntegration()]
sentry_sdk.init(
integrations=integrations,
sample_rate=SENTRY_SAMPLE_RATE,
traces_sample_rate=SENTRY_TRACE_SAMPLE_RATE,
environment=SENTRY_ENVIRONMENT,
send_default_pii=True,
)
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///:memory:"
app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
db = SQLAlchemy(app)
@app.route('/db')
def entry_point():
db.engine.execute("SELECT name FROM sqlite_master")
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
Expected Result
Sentry should correctly fetch the transaction name from the endpoint as well as capture spans that occurred during the request execution.
We expect the following in the performance tab. These screenshots are from running the same code but with the DebuggedApplication
line commented out:
Transaction View
Event Details
Actual Result
Sentry has the name of generic WSGI request
for all transactions in the performance tab of the dashboard. They're only differentiated by their HTTP Method. They also do not correctly include the Spans that make up a transaction.
Through debugging, I figured out that somehow the order of the steps is different. Having DebuggedApplication
active results in a Transaction.finish()
method being called before the transaction has had its name set here
Screenshots of actual result:
Performance:
Transaction
Event Details:
This is obviously not a big issue, however, as I did spent 3 days debugging it I wanted to document this behaviour in case someone else is also struggling with it.
Hey @BoyanYK
Thanks for reporting this. This can definitely be improved!
I also think it (hopefully) is not a big change to have proper data when DebuggedApplication
is enabled.
Could you submit a PR that fixes this? We are always happy to help merge the PR to improve integrations!
@BoyanYK After investigating this issue, we would recommend that you fix the issue by simply removing the app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
line from your code.
During our investigation, we discovered that the DebuggedApplication
line is redundant because when passing debug=True
to Flask's app.run
function, Flask already automatically wraps the application in Werkzeug's DebuggedApplication
internally. Using both the DebuggedApplication
and the debug=True
option causes the app to be double-wrapped in the debugger (you can observe this when starting the Flask app, since two different debugger PINs are outputted). As you already noted under the "Expected Results" of the issue, removing the DebuggedApplication
line fixes the issue with the transaction names that you observed, so we would recommend removing the line to fix the problem.
We are closing this issue for now because this double-wrapping of the Flask application in the DebuggedApplication
is not a supported use case, and in this case, the problem can be easily fixed by removing the DebuggedApplication
line and simply using Flask's debug=True
option.
However, if anyone observes a similar issue with some other Flask middleware, please feel free to submit a new issue which references this one.
Thanks for taking the time to follow up on this! This is an interesting finding I definitely wasn't aware of - that the application would be wrapped in a debugger twice - it does confirm that it isn't a bug.