Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flask] rewrite Flask integration #667

Merged
merged 82 commits into from Nov 6, 2018
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
0e87554
[flask] start work on new patch implementation
brettlangdon Oct 16, 2018
4c2d0d6
[flask] trace more internal parts
brettlangdon Oct 17, 2018
9de028e
[flask] trace more things
brettlangdon Oct 17, 2018
6a1a121
[flask] round out prototype of new tracing
brettlangdon Oct 17, 2018
15a2762
[flask] replace old patch.py with new_patch.py
brettlangdon Oct 17, 2018
93953ea
[flask] finish up prototype and deduplicate some code
brettlangdon Oct 18, 2018
ad8d1d4
[flask] move wrapper helpers to wrappers.py
brettlangdon Oct 18, 2018
75b8720
[flask] add docstrings
brettlangdon Oct 18, 2018
688448d
[flask] remove unused import
brettlangdon Oct 18, 2018
3c2e040
[flask] Update documentation
brettlangdon Oct 18, 2018
369a15f
[flask] < 0.12.0 does not have Flask.finalize_request
brettlangdon Oct 19, 2018
2978926
[flask] handle status code as a string
brettlangdon Oct 19, 2018
5a8540e
[flask] use config API
brettlangdon Oct 19, 2018
db3a626
[flask] update version parsing
brettlangdon Oct 19, 2018
f9ab7d2
[flask] patch signal receivers_for and add unpatch()
brettlangdon Oct 19, 2018
54d3463
[flask] add test for Flask signals
brettlangdon Oct 19, 2018
6d72c76
[flask] fix patching/unpatching lists
brettlangdon Oct 19, 2018
bf2a1d1
[flask] use template name as span resource name
brettlangdon Oct 19, 2018
a899b67
[flask] set test template directory
brettlangdon Oct 19, 2018
6d80afd
[flask] add test cases for Flask helpers
brettlangdon Oct 19, 2018
805e510
[flask] add test cases for Flask render functions
brettlangdon Oct 19, 2018
0cfb66a
[flask] add test helpers to check if something is wrapped
brettlangdon Oct 19, 2018
3b99172
[flask] simplify pin cloning logic
brettlangdon Oct 19, 2018
5f8ac2d
[flask] add blueprint tests
brettlangdon Oct 19, 2018
0564db2
[flask] rename patch.py to monkey.py
brettlangdon Oct 20, 2018
a5d8006
[flask] make sure do to do Pin(tracer=self.tracer) in tests
brettlangdon Oct 20, 2018
e126904
[flask] fix spelling
brettlangdon Oct 20, 2018
402ca93
[flask] add patch/unpatch idempotency tests
brettlangdon Oct 20, 2018
cc7cef4
[flask] add initial support for v0.9
brettlangdon Oct 20, 2018
822c9cc
[flask] update tests for v0.9
brettlangdon Oct 20, 2018
da81e19
[flask] use <= (0, 9) instead of == (0, 9)
brettlangdon Oct 20, 2018
c9f9705
[flask] fix signal names
brettlangdon Oct 20, 2018
77565c4
[flask] add assertion message
brettlangdon Oct 20, 2018
846ae04
[flask] skip send_from_directory
brettlangdon Oct 22, 2018
aba302a
[flask] add find_span_by_name test helper
brettlangdon Oct 22, 2018
4997d68
[flask] add error handler test cases
brettlangdon Oct 22, 2018
dcf0b68
[flask] Use start_response instead of Flask.finalize_request for resp…
brettlangdon Oct 22, 2018
faf2735
[flask] assert bytes equality
brettlangdon Oct 22, 2018
7624fed
[flask] add test caes for flask.views.View
brettlangdon Oct 22, 2018
56a52cc
[flask] enable by default
brettlangdon Oct 23, 2018
1f6c99a
[flask] remove large TODO comment
brettlangdon Oct 23, 2018
3ccbdae
[flask] change 404 resource name to '<method> 404'
brettlangdon Oct 23, 2018
845130c
[flask] fix py2 vs py3 base exception name
brettlangdon Oct 23, 2018
4ab892c
[flask] add request lifecycle tests
brettlangdon Oct 23, 2018
b26b3f1
[flask] support unicode
brettlangdon Oct 23, 2018
fed1e2c
[flask] rewrite Flask autopatch tests
brettlangdon Oct 23, 2018
40228b7
[flask] run py27-flask09 tests in circleci
brettlangdon Oct 23, 2018
25643f5
[flask] add static file tests
brettlangdon Oct 24, 2018
b46b761
[flask] rename monkey.py back to patch.py
brettlangdon Oct 25, 2018
3c566a8
[flask] update docstring for flask being enabled by default
brettlangdon Oct 25, 2018
f243f07
[flask] fix comments and docstrings
brettlangdon Oct 25, 2018
eb4a9b7
[flask] use ddtrace.utils.importlib.func_name
brettlangdon Oct 25, 2018
0b9280b
[core] modify Pin.get_from to accept multiple objects
brettlangdon Oct 26, 2018
56f5026
[flask] fix remaining get_arg_or_kwargs
brettlangdon Oct 29, 2018
cc80c54
[flask] only use '<method> 404' if the endpoint is unknown
brettlangdon Oct 29, 2018
ceb7e5a
[flask] use request.path for http.URL tag
brettlangdon Oct 29, 2018
dc1363f
[flask] remove/fix TODOs
brettlangdon Oct 30, 2018
b5a7ea4
[flask] Add Pin.find(*objs) helper
brettlangdon Oct 30, 2018
a73dae3
[flask] only use 'def _wrap()' where necessary
brettlangdon Oct 30, 2018
ce7638b
[flask] mark 5xx errors by default, allow config of additional error …
brettlangdon Oct 30, 2018
1951572
Update tests/contrib/flask/test_request.py
Kyle-Verhoog Oct 30, 2018
f3b257a
Update tests/contrib/flask/test_template.py
Kyle-Verhoog Oct 30, 2018
4a1ae19
Update tests/contrib/flask/test_template.py
Kyle-Verhoog Oct 30, 2018
469263d
Merge branch 'brettlangdon/flask-dev' of github.com:datadog/dd-trace-…
brettlangdon Oct 30, 2018
ed2326b
[flask] simplify fetching wrapped arg
brettlangdon Oct 30, 2018
a5697a3
[flask] fix spelling mistake
brettlangdon Oct 30, 2018
92f32a5
Update ddtrace/contrib/flask/patch.py
Kyle-Verhoog Oct 30, 2018
f878da4
[flask] remove unnecessary 'func_name(func)' call
brettlangdon Oct 30, 2018
a4e08db
Merge branch 'brettlangdon/flask-dev' of github.com:datadog/dd-trace-…
brettlangdon Oct 30, 2018
09b2b92
Update tests/contrib/flask/test_blueprint.py
Kyle-Verhoog Oct 30, 2018
8b1dcc4
[flask] fix remaining comments from kyle
brettlangdon Oct 30, 2018
d1507d7
Merge branch 'brettlangdon/flask-dev' of github.com:datadog/dd-trace-…
brettlangdon Oct 30, 2018
1797a60
[flask] fix flake8 issues
brettlangdon Oct 30, 2018
199406d
[flask] test distributed tracing
brettlangdon Oct 30, 2018
ed4a5bb
[flask] add find_span_parent helper
brettlangdon Oct 30, 2018
4afe310
[flask] add hook test cases
brettlangdon Oct 30, 2018
65f0c6b
[flask] fix spelling
brettlangdon Nov 1, 2018
25ae08c
[flask] rename Pin.find to Pin._find and add tests
brettlangdon Nov 1, 2018
a676d3c
[flask] one last Pin.find -> Pin._find
brettlangdon Nov 1, 2018
e4d6080
[flask] try to parse endpoint/url rule in Flask.preprocess_request as…
brettlangdon Nov 2, 2018
fcc7f6a
[flask] fix line too long issue
brettlangdon Nov 2, 2018
9fe7c7b
Merge branch '0.16-dev' into brettlangdon/flask-dev
brettlangdon Nov 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions .circleci/config.yml
Expand Up @@ -326,10 +326,12 @@ jobs:
- *restore_cache_step
- run: tox -e 'flask_contrib-{py27,py34,py35,py36}-flask{010,011,012,10}-blinker' --result-json /tmp/flask.1.results
- run: TOX_SKIP_DIST=False tox -e 'flask_contrib_autopatch-{py27,py34,py35,py36}-flask{010,011,012,10}-blinker' --result-json /tmp/flask.2.results
- run: tox -e 'flask_cache_contrib-{py27,py34,py35,py36}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker' --result-json /tmp/flask.3.results
- run: TOX_SKIP_DIST=False tox -e 'flask_cache_contrib_autopatch-{py27,py34,py35,py36}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker' --result-json /tmp/flask.4.results
- run: tox -e 'flask_cache_contrib-{py27}-flask{010,011}-flaskcache{012}-memcached-redis{210}-blinker' --result-json /tmp/flask.5.results
- run: TOX_SKIP_DIST=False tox -e 'flask_cache_contrib_autopatch-{py27}-flask{010,011}-flaskcache{012}-memcached-redis{210}-blinker' --result-json /tmp/flask.6.results
- run: tox -e 'flask_contrib-{py27}-flask{09}-blinker' --result-json /tmp/flask.3.results
- run: TOX_SKIP_DIST=False tox -e 'flask_contrib_autopatch-{py27}-flask{09}-blinker' --result-json /tmp/flask.4.results
- run: tox -e 'flask_cache_contrib-{py27,py34,py35,py36}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker' --result-json /tmp/flask.5.results
- run: TOX_SKIP_DIST=False tox -e 'flask_cache_contrib_autopatch-{py27,py34,py35,py36}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker' --result-json /tmp/flask.6.results
- run: tox -e 'flask_cache_contrib-{py27}-flask{010,011}-flaskcache{012}-memcached-redis{210}-blinker' --result-json /tmp/flask.7.results
- run: TOX_SKIP_DIST=False tox -e 'flask_cache_contrib_autopatch-{py27}-flask{010,011}-flaskcache{012}-memcached-redis{210}-blinker' --result-json /tmp/flask.8.results
- persist_to_workspace:
root: /tmp
paths:
Expand All @@ -339,6 +341,8 @@ jobs:
- flask.4.results
- flask.5.results
- flask.6.results
- flask.7.results
- flask.8.results
- *save_cache_step

gevent:
Expand Down
45 changes: 23 additions & 22 deletions ddtrace/contrib/flask/__init__.py
@@ -1,35 +1,32 @@
"""
The Flask trace middleware will track request timings and templates. It
requires the `Blinker <https://pythonhosted.org/blinker/>`_ library, which
Flask uses for signalling.
The `Flask <http://flask.pocoo.org/>`_ integration will add tracing to all requests to your Flask application.

To install the middleware, add::
This integration will track the entire Flask lifecycle including user-defined endpoints, hooks,
signals, and templating rendering.

from ddtrace import tracer
from ddtrace.contrib.flask import TraceMiddleware
To configure tracing manually::

and create a `TraceMiddleware` object::
from ddtrace import patch_all
patch_all()

traced_app = TraceMiddleware(app, tracer, service="my-flask-app", distributed_tracing=False)
from flask import Flask

Here is the end result, in a sample app::
app = Flask(__name__)

from flask import Flask
import blinker as _

from ddtrace import tracer
from ddtrace.contrib.flask import TraceMiddleware
@app.route('/')
def index():
return 'hello world'

app = Flask(__name__)

traced_app = TraceMiddleware(app, tracer, service="my-flask-app", distributed_tracing=False)
if __name__ == '__main__':
app.run()

@app.route("/")
def home():
return "hello world"

Set `distributed_tracing=True` if this is called remotely from an instrumented application.
We suggest to enable it only for internal services where headers are under your control.
You may also enable Flask tracing automatically via ddtrace-run::

ddtrace-run python app.py

"""

from ...utils.importlib import require_modules
Expand All @@ -39,7 +36,11 @@ def home():

with require_modules(required_modules) as missing_modules:
if not missing_modules:
# DEV: We do this so we can `@mock.patch('ddtrace.contrib.flask._patch.<func>')` in tests
from . import patch as _patch
from .middleware import TraceMiddleware
from .patch import patch

__all__ = ['TraceMiddleware', 'patch']
patch = _patch.patch
unpatch = _patch.unpatch

__all__ = ['TraceMiddleware', 'patch', 'unpatch']
44 changes: 44 additions & 0 deletions ddtrace/contrib/flask/helpers.py
@@ -0,0 +1,44 @@
from ddtrace import Pin
import flask


def get_current_app():
"""Helper to get the flask.app.Flask from the current app context"""
appctx = flask._app_ctx_stack.top
if appctx:
brettlangdon marked this conversation as resolved.
Show resolved Hide resolved
return appctx.app
return None


def with_instance_pin(func):
"""Helper to wrap a function wrapper and ensure an enabled pin is available for the `instance`"""
def wrapper(wrapped, instance, args, kwargs):
pin = Pin._find(wrapped, instance, get_current_app())
if not pin or not pin.enabled():
return wrapped(*args, **kwargs)

return func(pin, wrapped, instance, args, kwargs)
return wrapper


def simple_tracer(name, span_type=None):
"""Generate a simple tracer that wraps the function call with `with tracer.trace()`"""
@with_instance_pin
def wrapper(pin, wrapped, instance, args, kwargs):
with pin.tracer.trace(name, service=pin.service, span_type=span_type):
return wrapped(*args, **kwargs)
return wrapper


def get_current_span(pin, root=False):
"""Helper to get the current span from the provided pins current call context"""
if not pin or not pin.enabled():
return None

ctx = pin.tracer.get_call_context()
if not ctx:
return None

if root:
return ctx.get_current_root_span()
return ctx.get_current_span()
2 changes: 2 additions & 0 deletions ddtrace/contrib/flask/middleware.py
Expand Up @@ -3,6 +3,7 @@
from ... import compat
from ...ext import http, errors, AppTypes
from ...propagation.http import HTTPPropagator
from ...utils.deprecation import deprecated

import flask.templating
from flask import g, request, signals
Expand All @@ -16,6 +17,7 @@

class TraceMiddleware(object):

@deprecated(message='Use patching instead (see the docs).', version='1.0.0')
def __init__(self, app, tracer, service="flask", use_signals=True, distributed_tracing=False):
self.app = app
log.debug('flask: initializing trace middleware')
Expand Down