mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-28 20:52:57 +08:00
Removing support for python 2.7 (#2)
OpenTelemetry doesn't support Python 2.7. Removing it from the tests and removing contrib packages that don't support Python 3. In this change: - removing pylons contrib - removing mysqldb contrib - updating minimum versions of flask (>=1.0), gevent (>=1.1) Signed-off-by: Alex Boten <aboten@lightstep.com>
This commit is contained in:
@ -202,17 +202,6 @@ jobs:
|
|||||||
- *persist_to_workspace_step
|
- *persist_to_workspace_step
|
||||||
- *save_cache_step
|
- *save_cache_step
|
||||||
|
|
||||||
pylons:
|
|
||||||
docker:
|
|
||||||
- *test_runner
|
|
||||||
resource_class: *resource_class
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- *restore_cache_step
|
|
||||||
- run: scripts/run-tox-scenario '^pylons_contrib-'
|
|
||||||
- *persist_to_workspace_step
|
|
||||||
- *save_cache_step
|
|
||||||
|
|
||||||
aiohttp:
|
aiohttp:
|
||||||
docker:
|
docker:
|
||||||
- *test_runner
|
- *test_runner
|
||||||
@ -318,7 +307,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- *restore_cache_step
|
- *restore_cache_step
|
||||||
- run: tox -e 'falcon_contrib{,_autopatch}-{py27,py34,py35,py36}-falcon{10,11,12,13,14}' --result-json /tmp/falcon.results
|
- run: tox -e 'falcon_contrib{,_autopatch}-{py34,py35,py36}-falcon{10,11,12,13,14}' --result-json /tmp/falcon.results
|
||||||
- *persist_to_workspace_step
|
- *persist_to_workspace_step
|
||||||
- *save_cache_step
|
- *save_cache_step
|
||||||
|
|
||||||
@ -720,7 +709,7 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
command: |
|
command: |
|
||||||
mkdir -p /tmp/test-reports
|
mkdir -p /tmp/test-reports
|
||||||
tox -e 'benchmarks-{py27,py34,py35,py36,py37}' --result-json /tmp/benchmarks.results -- --benchmark-storage=file:///tmp/test-reports/ --benchmark-autosave
|
tox -e 'benchmarks-{py34,py35,py36,py37}' --result-json /tmp/benchmarks.results -- --benchmark-storage=file:///tmp/test-reports/ --benchmark-autosave
|
||||||
- store_test_results:
|
- store_test_results:
|
||||||
path: /tmp/test-reports
|
path: /tmp/test-reports
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
@ -985,10 +974,6 @@ workflows:
|
|||||||
requires:
|
requires:
|
||||||
- flake8
|
- flake8
|
||||||
- black
|
- black
|
||||||
- pylons:
|
|
||||||
requires:
|
|
||||||
- flake8
|
|
||||||
- black
|
|
||||||
- pymemcache:
|
- pymemcache:
|
||||||
requires:
|
requires:
|
||||||
- flake8
|
- flake8
|
||||||
@ -1097,7 +1082,6 @@ workflows:
|
|||||||
- opentracer
|
- opentracer
|
||||||
- psycopg
|
- psycopg
|
||||||
- pylibmc
|
- pylibmc
|
||||||
- pylons
|
|
||||||
- pymemcache
|
- pymemcache
|
||||||
- pymongo
|
- pymongo
|
||||||
- pymysql
|
- pymysql
|
||||||
|
@ -11,7 +11,7 @@ import sys
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
PY_DIR_PATTERN = re.compile(r"^py[23][0-9]$")
|
PY_DIR_PATTERN = re.compile(r"^py3[0-9]$")
|
||||||
|
|
||||||
|
|
||||||
# Determine if the folder should be ignored
|
# Determine if the folder should be ignored
|
||||||
@ -27,7 +27,6 @@ def pytest_ignore_collect(path, config):
|
|||||||
Example::
|
Example::
|
||||||
|
|
||||||
File: tests/contrib/vertica/py35/test.py
|
File: tests/contrib/vertica/py35/test.py
|
||||||
Python 2.7: Skip
|
|
||||||
Python 3.4: Skip
|
Python 3.4: Skip
|
||||||
Python 3.5: Collect
|
Python 3.5: Collect
|
||||||
Python 3.6: Collect
|
Python 3.6: Collect
|
||||||
|
@ -43,7 +43,6 @@ EXTRA_PATCHED_MODULES = {
|
|||||||
"django": True,
|
"django": True,
|
||||||
"falcon": True,
|
"falcon": True,
|
||||||
"flask": True,
|
"flask": True,
|
||||||
"pylons": True,
|
|
||||||
"pyramid": True,
|
"pyramid": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ Available environment variables:
|
|||||||
DATADOG_TRACE_AGENT_PORT=8126: override the port that the default tracer will submit to (default: 8126)
|
DATADOG_TRACE_AGENT_PORT=8126: override the port that the default tracer will submit to (default: 8126)
|
||||||
DATADOG_SERVICE_NAME : override the service name to be used for this program (no default)
|
DATADOG_SERVICE_NAME : override the service name to be used for this program (no default)
|
||||||
This value is passed through when setting up middleware for web framework integrations.
|
This value is passed through when setting up middleware for web framework integrations.
|
||||||
(e.g. pylons, flask, django)
|
(e.g. flask, django)
|
||||||
For tracing without a web integration, prefer setting the service name in code.
|
For tracing without a web integration, prefer setting the service name in code.
|
||||||
DATADOG_PRIORITY_SAMPLING=true|false : (default: false): enables Priority Sampling.
|
DATADOG_PRIORITY_SAMPLING=true|false : (default: false): enables Priority Sampling.
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
@ -156,13 +156,6 @@ def patch():
|
|||||||
for signal in signals:
|
for signal in signals:
|
||||||
module = 'flask'
|
module = 'flask'
|
||||||
|
|
||||||
# v0.9 missed importing `appcontext_tearing_down` in `flask/__init__.py`
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/__init__.py#L35-L37
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/signals.py#L52
|
|
||||||
# DEV: Version 0.9 doesn't have a patch version
|
|
||||||
if flask_version <= (0, 9) and signal == 'appcontext_tearing_down':
|
|
||||||
module = 'flask.signals'
|
|
||||||
|
|
||||||
# DEV: Patch `receivers_for` instead of `connect` to ensure we don't mess with `disconnect`
|
# DEV: Patch `receivers_for` instead of `connect` to ensure we don't mess with `disconnect`
|
||||||
_w(module, '{}.receivers_for'.format(signal), traced_signal_receivers_for(signal))
|
_w(module, '{}.receivers_for'.format(signal), traced_signal_receivers_for(signal))
|
||||||
|
|
||||||
@ -241,13 +234,6 @@ def unpatch():
|
|||||||
# Handle 'flask.request_started.receivers_for'
|
# Handle 'flask.request_started.receivers_for'
|
||||||
obj = flask
|
obj = flask
|
||||||
|
|
||||||
# v0.9.0 missed importing `appcontext_tearing_down` in `flask/__init__.py`
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/__init__.py#L35-L37
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/signals.py#L52
|
|
||||||
# DEV: Version 0.9 doesn't have a patch version
|
|
||||||
if flask_version <= (0, 9) and prop == 'appcontext_tearing_down.receivers_for':
|
|
||||||
obj = flask.signals
|
|
||||||
|
|
||||||
if '.' in prop:
|
if '.' in prop:
|
||||||
attr, _, prop = prop.partition('.')
|
attr, _, prop = prop.partition('.')
|
||||||
obj = getattr(obj, attr, object())
|
obj = getattr(obj, attr, object())
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
"""
|
|
||||||
The pylons trace middleware will track request timings. To
|
|
||||||
install the middleware, prepare your WSGI application and do
|
|
||||||
the following::
|
|
||||||
|
|
||||||
from pylons.wsgiapp import PylonsApp
|
|
||||||
|
|
||||||
from ddtrace import tracer
|
|
||||||
from ddtrace.contrib.pylons import PylonsTraceMiddleware
|
|
||||||
|
|
||||||
app = PylonsApp(...)
|
|
||||||
|
|
||||||
traced_app = PylonsTraceMiddleware(app, tracer, service='my-pylons-app')
|
|
||||||
|
|
||||||
Then you can define your routes and views as usual.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ...utils.importlib import require_modules
|
|
||||||
|
|
||||||
|
|
||||||
required_modules = ['pylons.wsgiapp']
|
|
||||||
|
|
||||||
with require_modules(required_modules) as missing_modules:
|
|
||||||
if not missing_modules:
|
|
||||||
from .middleware import PylonsTraceMiddleware
|
|
||||||
from .patch import patch, unpatch
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'patch',
|
|
||||||
'unpatch',
|
|
||||||
'PylonsTraceMiddleware',
|
|
||||||
]
|
|
@ -1,8 +0,0 @@
|
|||||||
try:
|
|
||||||
from pylons.templating import render_mako # noqa
|
|
||||||
|
|
||||||
# Pylons > 0.9.7
|
|
||||||
legacy_pylons = False
|
|
||||||
except ImportError:
|
|
||||||
# Pylons <= 0.9.7
|
|
||||||
legacy_pylons = True
|
|
@ -1 +0,0 @@
|
|||||||
CONFIG_MIDDLEWARE = '__datadog_middleware'
|
|
@ -1,110 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from webob import Request
|
|
||||||
from pylons import config
|
|
||||||
|
|
||||||
from .renderer import trace_rendering
|
|
||||||
from .constants import CONFIG_MIDDLEWARE
|
|
||||||
|
|
||||||
from ...compat import reraise
|
|
||||||
from ...constants import ANALYTICS_SAMPLE_RATE_KEY
|
|
||||||
from ...ext import SpanTypes, http
|
|
||||||
from ...internal.logger import get_logger
|
|
||||||
from ...propagation.http import HTTPPropagator
|
|
||||||
from ...settings import config as ddconfig
|
|
||||||
|
|
||||||
|
|
||||||
log = get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class PylonsTraceMiddleware(object):
|
|
||||||
|
|
||||||
def __init__(self, app, tracer, service='pylons', distributed_tracing=True):
|
|
||||||
self.app = app
|
|
||||||
self._service = service
|
|
||||||
self._distributed_tracing = distributed_tracing
|
|
||||||
self._tracer = tracer
|
|
||||||
|
|
||||||
# register middleware reference
|
|
||||||
config[CONFIG_MIDDLEWARE] = self
|
|
||||||
|
|
||||||
# add template tracing
|
|
||||||
trace_rendering()
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
if self._distributed_tracing:
|
|
||||||
# retrieve distributed tracing headers
|
|
||||||
request = Request(environ)
|
|
||||||
propagator = HTTPPropagator()
|
|
||||||
context = propagator.extract(request.headers)
|
|
||||||
# only need to active the new context if something was propagated
|
|
||||||
if context.trace_id:
|
|
||||||
self._tracer.context_provider.activate(context)
|
|
||||||
|
|
||||||
with self._tracer.trace('pylons.request', service=self._service, span_type=SpanTypes.WEB) as span:
|
|
||||||
# Set the service in tracer.trace() as priority sampling requires it to be
|
|
||||||
# set as early as possible when different services share one single agent.
|
|
||||||
|
|
||||||
# set analytics sample rate with global config enabled
|
|
||||||
span.set_tag(
|
|
||||||
ANALYTICS_SAMPLE_RATE_KEY,
|
|
||||||
ddconfig.pylons.get_analytics_sample_rate(use_global_config=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
if not span.sampled:
|
|
||||||
return self.app(environ, start_response)
|
|
||||||
|
|
||||||
# tentative on status code, otherwise will be caught by except below
|
|
||||||
def _start_response(status, *args, **kwargs):
|
|
||||||
""" a patched response callback which will pluck some metadata. """
|
|
||||||
http_code = int(status.split()[0])
|
|
||||||
span.set_tag(http.STATUS_CODE, http_code)
|
|
||||||
if http_code >= 500:
|
|
||||||
span.error = 1
|
|
||||||
return start_response(status, *args, **kwargs)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return self.app(environ, _start_response)
|
|
||||||
except Exception as e:
|
|
||||||
# store current exceptions info so we can re-raise it later
|
|
||||||
(typ, val, tb) = sys.exc_info()
|
|
||||||
|
|
||||||
# e.code can either be a string or an int
|
|
||||||
code = getattr(e, 'code', 500)
|
|
||||||
try:
|
|
||||||
code = int(code)
|
|
||||||
if not 100 <= code < 600:
|
|
||||||
code = 500
|
|
||||||
except Exception:
|
|
||||||
code = 500
|
|
||||||
span.set_tag(http.STATUS_CODE, code)
|
|
||||||
span.error = 1
|
|
||||||
|
|
||||||
# re-raise the original exception with its original traceback
|
|
||||||
reraise(typ, val, tb=tb)
|
|
||||||
except SystemExit:
|
|
||||||
span.set_tag(http.STATUS_CODE, 500)
|
|
||||||
span.error = 1
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
controller = environ.get('pylons.routes_dict', {}).get('controller')
|
|
||||||
action = environ.get('pylons.routes_dict', {}).get('action')
|
|
||||||
|
|
||||||
# There are cases where users re-route requests and manually
|
|
||||||
# set resources. If this is so, don't do anything, otherwise
|
|
||||||
# set the resource to the controller / action that handled it.
|
|
||||||
if span.resource == span.name:
|
|
||||||
span.resource = '%s.%s' % (controller, action)
|
|
||||||
|
|
||||||
span.set_tags({
|
|
||||||
http.METHOD: environ.get('REQUEST_METHOD'),
|
|
||||||
http.URL: '%s://%s:%s%s' % (environ.get('wsgi.url_scheme'),
|
|
||||||
environ.get('SERVER_NAME'),
|
|
||||||
environ.get('SERVER_PORT'),
|
|
||||||
environ.get('PATH_INFO')),
|
|
||||||
'pylons.user': environ.get('REMOTE_USER', ''),
|
|
||||||
'pylons.route.controller': controller,
|
|
||||||
'pylons.route.action': action,
|
|
||||||
})
|
|
||||||
if ddconfig.pylons.trace_query_string:
|
|
||||||
span.set_tag(http.QUERY_STRING, environ.get('QUERY_STRING'))
|
|
@ -1,41 +0,0 @@
|
|||||||
import os
|
|
||||||
from ddtrace.vendor import wrapt
|
|
||||||
import pylons.wsgiapp
|
|
||||||
|
|
||||||
from ddtrace import tracer, Pin
|
|
||||||
|
|
||||||
from .middleware import PylonsTraceMiddleware
|
|
||||||
from ...utils.formats import asbool, get_env
|
|
||||||
from ...utils.wrappers import unwrap as _u
|
|
||||||
|
|
||||||
|
|
||||||
def patch():
|
|
||||||
"""Instrument Pylons applications"""
|
|
||||||
if getattr(pylons.wsgiapp, '_datadog_patch', False):
|
|
||||||
return
|
|
||||||
|
|
||||||
setattr(pylons.wsgiapp, '_datadog_patch', True)
|
|
||||||
wrapt.wrap_function_wrapper('pylons.wsgiapp', 'PylonsApp.__init__', traced_init)
|
|
||||||
|
|
||||||
|
|
||||||
def unpatch():
|
|
||||||
"""Disable Pylons tracing"""
|
|
||||||
if not getattr(pylons.wsgiapp, '__datadog_patch', False):
|
|
||||||
return
|
|
||||||
setattr(pylons.wsgiapp, '__datadog_patch', False)
|
|
||||||
|
|
||||||
_u(pylons.wsgiapp.PylonsApp, '__init__')
|
|
||||||
|
|
||||||
|
|
||||||
def traced_init(wrapped, instance, args, kwargs):
|
|
||||||
wrapped(*args, **kwargs)
|
|
||||||
|
|
||||||
# set tracing options and create the TraceMiddleware
|
|
||||||
service = os.environ.get('DATADOG_SERVICE_NAME', 'pylons')
|
|
||||||
distributed_tracing = asbool(get_env('pylons', 'distributed_tracing', True))
|
|
||||||
Pin(service=service, tracer=tracer).onto(instance)
|
|
||||||
traced_app = PylonsTraceMiddleware(instance, tracer, service=service, distributed_tracing=distributed_tracing)
|
|
||||||
|
|
||||||
# re-order the middleware stack so that the first middleware is ours
|
|
||||||
traced_app.app = instance.app
|
|
||||||
instance.app = traced_app
|
|
@ -1,36 +0,0 @@
|
|||||||
import pylons
|
|
||||||
|
|
||||||
from pylons import config
|
|
||||||
|
|
||||||
from ddtrace.vendor.wrapt import wrap_function_wrapper as _w
|
|
||||||
|
|
||||||
from .compat import legacy_pylons
|
|
||||||
from .constants import CONFIG_MIDDLEWARE
|
|
||||||
|
|
||||||
|
|
||||||
def trace_rendering():
|
|
||||||
"""Patch all Pylons renderers. It supports multiple versions
|
|
||||||
of Pylons and multiple renderers.
|
|
||||||
"""
|
|
||||||
# patch only once
|
|
||||||
if getattr(pylons.templating, '__datadog_patch', False):
|
|
||||||
return
|
|
||||||
setattr(pylons.templating, '__datadog_patch', True)
|
|
||||||
|
|
||||||
if legacy_pylons:
|
|
||||||
# Pylons <= 0.9.7
|
|
||||||
_w('pylons.templating', 'render', _traced_renderer)
|
|
||||||
else:
|
|
||||||
# Pylons > 0.9.7
|
|
||||||
_w('pylons.templating', 'render_mako', _traced_renderer)
|
|
||||||
_w('pylons.templating', 'render_mako_def', _traced_renderer)
|
|
||||||
_w('pylons.templating', 'render_genshi', _traced_renderer)
|
|
||||||
_w('pylons.templating', 'render_jinja2', _traced_renderer)
|
|
||||||
|
|
||||||
|
|
||||||
def _traced_renderer(wrapped, instance, args, kwargs):
|
|
||||||
"""Traced renderer"""
|
|
||||||
tracer = config[CONFIG_MIDDLEWARE]._tracer
|
|
||||||
with tracer.trace('pylons.render') as span:
|
|
||||||
span.set_tag('template.name', args[0])
|
|
||||||
return wrapped(*args, **kwargs)
|
|
@ -57,7 +57,6 @@ PATCH_MODULES = {
|
|||||||
# Ignore some web framework integrations that might be configured explicitly in code
|
# Ignore some web framework integrations that might be configured explicitly in code
|
||||||
'django': False,
|
'django': False,
|
||||||
'falcon': False,
|
'falcon': False,
|
||||||
'pylons': False,
|
|
||||||
'pyramid': False,
|
'pyramid': False,
|
||||||
|
|
||||||
# Standard library modules off by default
|
# Standard library modules off by default
|
||||||
|
@ -52,8 +52,6 @@ Supported web frameworks:
|
|||||||
+-------------------+---------+
|
+-------------------+---------+
|
||||||
| :ref:`flask` | True |
|
| :ref:`flask` | True |
|
||||||
+-------------------+---------+
|
+-------------------+---------+
|
||||||
| :ref:`pylons` | True |
|
|
||||||
+-------------------+---------+
|
|
||||||
| :ref:`pyramid` | True |
|
| :ref:`pyramid` | True |
|
||||||
+-------------------+---------+
|
+-------------------+---------+
|
||||||
| :ref:`requests` | True |
|
| :ref:`requests` | True |
|
||||||
@ -197,7 +195,6 @@ Enabling APM events for all web frameworks can be accomplished by setting the en
|
|||||||
* :ref:`falcon`
|
* :ref:`falcon`
|
||||||
* :ref:`flask`
|
* :ref:`flask`
|
||||||
* :ref:`molten`
|
* :ref:`molten`
|
||||||
* :ref:`pylons`
|
|
||||||
* :ref:`pyramid`
|
* :ref:`pyramid`
|
||||||
* :ref:`requests`
|
* :ref:`requests`
|
||||||
* :ref:`tornado`
|
* :ref:`tornado`
|
||||||
@ -238,8 +235,6 @@ For most libraries, APM events can be enabled with the environment variable ``DD
|
|||||||
+----------------------+----------------------------------------+
|
+----------------------+----------------------------------------+
|
||||||
| :ref:`pylibmc` | ``DD_PYLIBMC_ANALYTICS_ENABLED`` |
|
| :ref:`pylibmc` | ``DD_PYLIBMC_ANALYTICS_ENABLED`` |
|
||||||
+----------------------+----------------------------------------+
|
+----------------------+----------------------------------------+
|
||||||
| :ref:`pylons` | ``DD_PYLONS_ANALYTICS_ENABLED`` |
|
|
||||||
+----------------------+----------------------------------------+
|
|
||||||
| :ref:`pymemcache` | ``DD_PYMEMCACHE_ANALYTICS_ENABLED`` |
|
| :ref:`pymemcache` | ``DD_PYMEMCACHE_ANALYTICS_ENABLED`` |
|
||||||
+----------------------+----------------------------------------+
|
+----------------------+----------------------------------------+
|
||||||
| :ref:`pymongo` | ``DD_PYMONGO_ANALYTICS_ENABLED`` |
|
| :ref:`pymongo` | ``DD_PYMONGO_ANALYTICS_ENABLED`` |
|
||||||
@ -564,7 +559,7 @@ The available environment variables for ``ddtrace-run`` are:
|
|||||||
the tracer
|
the tracer
|
||||||
* ``DATADOG_SERVICE_NAME`` (no default): override the service name to be used
|
* ``DATADOG_SERVICE_NAME`` (no default): override the service name to be used
|
||||||
for this program. This value is passed through when setting up middleware for
|
for this program. This value is passed through when setting up middleware for
|
||||||
web framework integrations (e.g. pylons, flask, django). For tracing without a
|
web framework integrations (e.g. flask, django). For tracing without a
|
||||||
web integration, prefer setting the service name in code.
|
web integration, prefer setting the service name in code.
|
||||||
* ``DATADOG_PATCH_MODULES=module:patch,module:patch...`` e.g.
|
* ``DATADOG_PATCH_MODULES=module:patch,module:patch...`` e.g.
|
||||||
``boto:true,redis:false``: override the modules patched for this execution of
|
``boto:true,redis:false``: override the modules patched for this execution of
|
||||||
|
@ -25,7 +25,7 @@ documentation`_.
|
|||||||
Supported Libraries
|
Supported Libraries
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
We officially support Python 2.7, 3.4 and above.
|
We officially support Python 3.4 and above.
|
||||||
|
|
||||||
The versions listed are the versions that we have tested, but ``ddtrace`` can
|
The versions listed are the versions that we have tested, but ``ddtrace`` can
|
||||||
still be compatible with other versions of these libraries. If a version of a
|
still be compatible with other versions of these libraries. If a version of a
|
||||||
@ -72,7 +72,7 @@ contacting support.
|
|||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`flask_cache` | >= 0.12 | No |
|
| :ref:`flask_cache` | >= 0.12 | No |
|
||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`gevent` | >= 1.0 | No |
|
| :ref:`gevent` | >= 1.1 | No |
|
||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`grpc` | >= 1.8.0 | Yes |
|
| :ref:`grpc` | >= 1.8.0 | Yes |
|
||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
@ -96,8 +96,6 @@ contacting support.
|
|||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`pylibmc` | >= 1.4 | Yes |
|
| :ref:`pylibmc` | >= 1.4 | Yes |
|
||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`pylons` | >= 0.9.6 | No |
|
|
||||||
+--------------------------------------------------+---------------+----------------+
|
|
||||||
| :ref:`pymemcache` | >= 1.3 | Yes |
|
| :ref:`pymemcache` | >= 1.3 | Yes |
|
||||||
+--------------------------------------------------+---------------+----------------+
|
+--------------------------------------------------+---------------+----------------+
|
||||||
| :ref:`pymongo` | >= 3.0 | Yes |
|
| :ref:`pymongo` | >= 3.0 | Yes |
|
||||||
|
@ -59,14 +59,6 @@ Molten
|
|||||||
|
|
||||||
.. automodule:: ddtrace.contrib.molten
|
.. automodule:: ddtrace.contrib.molten
|
||||||
|
|
||||||
.. _pylons:
|
|
||||||
|
|
||||||
Pylons
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
.. automodule:: ddtrace.contrib.pylons
|
|
||||||
|
|
||||||
|
|
||||||
.. _pyramid:
|
.. _pyramid:
|
||||||
|
|
||||||
Pyramid
|
Pyramid
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
target_version = ['py27', 'py34', 'py35', 'py36', 'py37', 'py38']
|
target_version = ['py34', 'py35', 'py36', 'py37', 'py38']
|
||||||
exclude = '''
|
exclude = '''
|
||||||
(
|
(
|
||||||
\.eggs
|
\.eggs
|
||||||
@ -70,7 +70,6 @@ exclude = '''
|
|||||||
| mysqldb
|
| mysqldb
|
||||||
| psycopg
|
| psycopg
|
||||||
| pylibmc
|
| pylibmc
|
||||||
| pylons
|
|
||||||
| pymemcache
|
| pymemcache
|
||||||
| pymongo
|
| pymongo
|
||||||
| pymysql
|
| pymysql
|
||||||
@ -140,7 +139,6 @@ exclude = '''
|
|||||||
| patch.py
|
| patch.py
|
||||||
| psycopg
|
| psycopg
|
||||||
| pylibmc
|
| pylibmc
|
||||||
| pylons
|
|
||||||
| pymemcache
|
| pymemcache
|
||||||
| pymongo
|
| pymongo
|
||||||
| pymysql
|
| pymysql
|
||||||
|
3
setup.py
3
setup.py
@ -88,7 +88,7 @@ documentation][visualization docs].
|
|||||||
|
|
||||||
# enum34 is an enum backport for earlier versions of python
|
# enum34 is an enum backport for earlier versions of python
|
||||||
# funcsigs backport required for vendored debtcollector
|
# funcsigs backport required for vendored debtcollector
|
||||||
install_requires = ["psutil>=5.0.0", "enum34; python_version<'3.4'", "funcsigs>=1.0.0;python_version=='2.7'"]
|
install_requires = ["psutil>=5.0.0", "enum34; python_version<'3.4'"]
|
||||||
|
|
||||||
# Base `setup()` kwargs without any C-extension registering
|
# Base `setup()` kwargs without any C-extension registering
|
||||||
setup_kwargs = dict(
|
setup_kwargs = dict(
|
||||||
@ -113,7 +113,6 @@ setup_kwargs = dict(
|
|||||||
entry_points={"console_scripts": ["ddtrace-run = ddtrace.commands.ddtrace_run:main"]},
|
entry_points={"console_scripts": ["ddtrace-run = ddtrace.commands.ddtrace_run:main"]},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 2.7",
|
|
||||||
"Programming Language :: Python :: 3.4",
|
"Programming Language :: Python :: 3.4",
|
||||||
"Programming Language :: Python :: 3.5",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
|
@ -11,12 +11,6 @@ from . import BaseFlaskTestCase
|
|||||||
|
|
||||||
class FlaskSignalsTestCase(BaseFlaskTestCase):
|
class FlaskSignalsTestCase(BaseFlaskTestCase):
|
||||||
def get_signal(self, signal_name):
|
def get_signal(self, signal_name):
|
||||||
# v0.9 missed importing `appcontext_tearing_down` in `flask/__init__.py`
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/__init__.py#L35-L37
|
|
||||||
# https://github.com/pallets/flask/blob/0.9/flask/signals.py#L52
|
|
||||||
# DEV: Version 0.9 doesn't have a patch version
|
|
||||||
if flask_version <= (0, 9) and signal_name == 'appcontext_tearing_down':
|
|
||||||
return getattr(flask.signals, signal_name)
|
|
||||||
return getattr(flask, signal_name)
|
return getattr(flask, signal_name)
|
||||||
|
|
||||||
def signal_function(self, name):
|
def signal_function(self, name):
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
from pylons.controllers import WSGIController
|
|
||||||
|
|
||||||
from ..lib.helpers import ExceptionWithCodeMethod, get_render_fn
|
|
||||||
|
|
||||||
|
|
||||||
class BaseController(WSGIController):
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
"""Invoke the Controller"""
|
|
||||||
# WSGIController.__call__ dispatches to the Controller method
|
|
||||||
# the request is routed to. This routing information is
|
|
||||||
# available in environ['pylons.routes_dict']
|
|
||||||
return WSGIController.__call__(self, environ, start_response)
|
|
||||||
|
|
||||||
|
|
||||||
class RootController(BaseController):
|
|
||||||
"""Controller used for most tests"""
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
return 'Hello World'
|
|
||||||
|
|
||||||
def raise_exception(self):
|
|
||||||
raise Exception('Ouch!')
|
|
||||||
|
|
||||||
def raise_wrong_code(self):
|
|
||||||
e = Exception('Ouch!')
|
|
||||||
e.code = 'wrong formatted code'
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def raise_code_method(self):
|
|
||||||
raise ExceptionWithCodeMethod('Ouch!')
|
|
||||||
|
|
||||||
def raise_custom_code(self):
|
|
||||||
e = Exception('Ouch!')
|
|
||||||
e.code = '512'
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def render(self):
|
|
||||||
render = get_render_fn()
|
|
||||||
return render('/template.mako')
|
|
||||||
|
|
||||||
def render_exception(self):
|
|
||||||
render = get_render_fn()
|
|
||||||
return render('/exception.mako')
|
|
@ -1 +0,0 @@
|
|||||||
# this file is required when Pylons calls the `legacy` module
|
|
@ -1,29 +0,0 @@
|
|||||||
from webhelpers import * # noqa
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionWithCodeMethod(Exception):
|
|
||||||
"""Use case where the status code is defined by
|
|
||||||
the `code()` method.
|
|
||||||
"""
|
|
||||||
def __init__(self, message):
|
|
||||||
super(ExceptionWithCodeMethod, self).__init__(message)
|
|
||||||
|
|
||||||
def code():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AppGlobals(object):
|
|
||||||
"""Object used to store application globals."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def get_render_fn():
|
|
||||||
"""Re-import the function everytime so that double-patching
|
|
||||||
is correctly tested.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
from pylons.templating import render_mako as render
|
|
||||||
except ImportError:
|
|
||||||
from pylons.templating import render
|
|
||||||
|
|
||||||
return render
|
|
@ -1,43 +0,0 @@
|
|||||||
from webob import Request, Response
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionMiddleware(object):
|
|
||||||
"""A middleware which raises an exception."""
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
raise Exception('Middleware exception')
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionToSuccessMiddleware(object):
|
|
||||||
"""A middleware which catches any exceptions that occur in a later
|
|
||||||
middleware and returns a successful request.
|
|
||||||
"""
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
req = Request(environ)
|
|
||||||
try:
|
|
||||||
response = req.get_response(self.app)
|
|
||||||
except Exception:
|
|
||||||
response = Response()
|
|
||||||
response.status_int = 200
|
|
||||||
response.body = 'An error has been handled appropriately'
|
|
||||||
return response(environ, start_response)
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionToClientErrorMiddleware(object):
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
req = Request(environ)
|
|
||||||
try:
|
|
||||||
response = req.get_response(self.app)
|
|
||||||
except Exception:
|
|
||||||
response = Response()
|
|
||||||
response.status_int = 404
|
|
||||||
response.body = 'An error has occured with proper client error handling'
|
|
||||||
return response(environ, start_response)
|
|
@ -1,20 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from routes import Mapper
|
|
||||||
|
|
||||||
|
|
||||||
def create_routes():
|
|
||||||
"""Change this function if you need to add more routes
|
|
||||||
to your Pylons test app.
|
|
||||||
"""
|
|
||||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
controller_dir = os.path.join(app_dir, 'controllers')
|
|
||||||
routes = Mapper(directory=controller_dir)
|
|
||||||
routes.connect('/', controller='root', action='index')
|
|
||||||
routes.connect('/raise_exception', controller='root', action='raise_exception')
|
|
||||||
routes.connect('/raise_wrong_code', controller='root', action='raise_wrong_code')
|
|
||||||
routes.connect('/raise_custom_code', controller='root', action='raise_custom_code')
|
|
||||||
routes.connect('/raise_code_method', controller='root', action='raise_code_method')
|
|
||||||
routes.connect('/render', controller='root', action='render')
|
|
||||||
routes.connect('/render_exception', controller='root', action='render_exception')
|
|
||||||
return routes
|
|
@ -1 +0,0 @@
|
|||||||
${1/0}
|
|
@ -1 +0,0 @@
|
|||||||
Hello world!
|
|
@ -1,41 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from mako.lookup import TemplateLookup
|
|
||||||
|
|
||||||
from pylons import config
|
|
||||||
from pylons.wsgiapp import PylonsApp
|
|
||||||
|
|
||||||
from routes.middleware import RoutesMiddleware
|
|
||||||
from beaker.middleware import SessionMiddleware, CacheMiddleware
|
|
||||||
|
|
||||||
from paste.registry import RegistryManager
|
|
||||||
|
|
||||||
from .router import create_routes
|
|
||||||
from .lib.helpers import AppGlobals
|
|
||||||
|
|
||||||
|
|
||||||
def make_app(global_conf, full_stack=True, **app_conf):
|
|
||||||
# load Pylons environment
|
|
||||||
root = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
paths = dict(
|
|
||||||
templates=[os.path.join(root, 'templates')],
|
|
||||||
)
|
|
||||||
config.init_app(global_conf, app_conf, paths=paths)
|
|
||||||
config['pylons.package'] = 'tests.contrib.pylons.app'
|
|
||||||
config['pylons.app_globals'] = AppGlobals()
|
|
||||||
|
|
||||||
# set Pylons routes
|
|
||||||
config['routes.map'] = create_routes()
|
|
||||||
|
|
||||||
# Create the Mako TemplateLookup, with the default auto-escaping
|
|
||||||
config['pylons.app_globals'].mako_lookup = TemplateLookup(
|
|
||||||
directories=paths['templates'],
|
|
||||||
)
|
|
||||||
|
|
||||||
# define a default middleware stack
|
|
||||||
app = PylonsApp()
|
|
||||||
app = RoutesMiddleware(app, config['routes.map'])
|
|
||||||
app = SessionMiddleware(app, config)
|
|
||||||
app = CacheMiddleware(app, config)
|
|
||||||
app = RegistryManager(app)
|
|
||||||
return app
|
|
@ -1,9 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
debug = false
|
|
||||||
|
|
||||||
[app:main]
|
|
||||||
use = call:tests.contrib.pylons.app.web:make_app
|
|
||||||
full_stack = true
|
|
||||||
cache_dir = %(here)s/.cache
|
|
||||||
beaker.session.key = helloworld
|
|
||||||
beaker.session.secret = somesecret
|
|
@ -1,429 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from routes import url_for
|
|
||||||
from paste import fixture
|
|
||||||
from paste.deploy import loadapp
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from ddtrace import config
|
|
||||||
from ddtrace.ext import http, errors
|
|
||||||
from ddtrace.constants import SAMPLING_PRIORITY_KEY, ANALYTICS_SAMPLE_RATE_KEY
|
|
||||||
from ddtrace.contrib.pylons import PylonsTraceMiddleware
|
|
||||||
|
|
||||||
from tests.opentracer.utils import init_tracer
|
|
||||||
from ...base import BaseTracerTestCase
|
|
||||||
from ...utils import assert_span_http_status_code
|
|
||||||
|
|
||||||
|
|
||||||
class PylonsTestCase(BaseTracerTestCase):
|
|
||||||
"""Pylons Test Controller that is used to test specific
|
|
||||||
cases defined in the Pylons controller. To test a new behavior,
|
|
||||||
add a new action in the `app.controllers.root` module.
|
|
||||||
"""
|
|
||||||
conf_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(PylonsTestCase, self).setUp()
|
|
||||||
# initialize a real traced Pylons app
|
|
||||||
wsgiapp = loadapp('config:test.ini', relative_to=PylonsTestCase.conf_dir)
|
|
||||||
self._wsgiapp = wsgiapp
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
self.app = fixture.TestApp(app)
|
|
||||||
|
|
||||||
def test_controller_exception(self):
|
|
||||||
"""Ensure exceptions thrown in controllers can be handled.
|
|
||||||
|
|
||||||
No error tags should be set in the span.
|
|
||||||
"""
|
|
||||||
from .app.middleware import ExceptionToSuccessMiddleware
|
|
||||||
wsgiapp = ExceptionToSuccessMiddleware(self._wsgiapp)
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
|
|
||||||
app = fixture.TestApp(app)
|
|
||||||
app.get(url_for(controller='root', action='raise_exception'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_exception'
|
|
||||||
assert span.error == 0
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/raise_exception'
|
|
||||||
assert_span_http_status_code(span, 200)
|
|
||||||
assert http.QUERY_STRING not in span.meta
|
|
||||||
assert span.get_tag(errors.ERROR_MSG) is None
|
|
||||||
assert span.get_tag(errors.ERROR_TYPE) is None
|
|
||||||
assert span.get_tag(errors.ERROR_STACK) is None
|
|
||||||
assert span.span_type == 'web'
|
|
||||||
|
|
||||||
def test_mw_exc_success(self):
|
|
||||||
"""Ensure exceptions can be properly handled by other middleware.
|
|
||||||
|
|
||||||
No error should be reported in the span.
|
|
||||||
"""
|
|
||||||
from .app.middleware import ExceptionMiddleware, ExceptionToSuccessMiddleware
|
|
||||||
wsgiapp = ExceptionMiddleware(self._wsgiapp)
|
|
||||||
wsgiapp = ExceptionToSuccessMiddleware(wsgiapp)
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
app = fixture.TestApp(app)
|
|
||||||
|
|
||||||
app.get(url_for(controller='root', action='index'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'None.None'
|
|
||||||
assert span.error == 0
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/'
|
|
||||||
assert_span_http_status_code(span, 200)
|
|
||||||
assert span.get_tag(errors.ERROR_MSG) is None
|
|
||||||
assert span.get_tag(errors.ERROR_TYPE) is None
|
|
||||||
assert span.get_tag(errors.ERROR_STACK) is None
|
|
||||||
|
|
||||||
def test_middleware_exception(self):
|
|
||||||
"""Ensure exceptions raised in middleware are properly handled.
|
|
||||||
|
|
||||||
Uncaught exceptions should result in error tagged spans.
|
|
||||||
"""
|
|
||||||
from .app.middleware import ExceptionMiddleware
|
|
||||||
wsgiapp = ExceptionMiddleware(self._wsgiapp)
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
app = fixture.TestApp(app)
|
|
||||||
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
app.get(url_for(controller='root', action='index'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'None.None'
|
|
||||||
assert span.error == 1
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/'
|
|
||||||
assert_span_http_status_code(span, 500)
|
|
||||||
assert span.get_tag(errors.ERROR_MSG) == 'Middleware exception'
|
|
||||||
assert span.get_tag(errors.ERROR_TYPE) == 'exceptions.Exception'
|
|
||||||
assert span.get_tag(errors.ERROR_STACK)
|
|
||||||
|
|
||||||
def test_exc_success(self):
|
|
||||||
from .app.middleware import ExceptionToSuccessMiddleware
|
|
||||||
wsgiapp = ExceptionToSuccessMiddleware(self._wsgiapp)
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
app = fixture.TestApp(app)
|
|
||||||
|
|
||||||
app.get(url_for(controller='root', action='raise_exception'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_exception'
|
|
||||||
assert span.error == 0
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/raise_exception'
|
|
||||||
assert_span_http_status_code(span, 200)
|
|
||||||
assert span.get_tag(errors.ERROR_MSG) is None
|
|
||||||
assert span.get_tag(errors.ERROR_TYPE) is None
|
|
||||||
assert span.get_tag(errors.ERROR_STACK) is None
|
|
||||||
|
|
||||||
def test_exc_client_failure(self):
|
|
||||||
from .app.middleware import ExceptionToClientErrorMiddleware
|
|
||||||
wsgiapp = ExceptionToClientErrorMiddleware(self._wsgiapp)
|
|
||||||
app = PylonsTraceMiddleware(wsgiapp, self.tracer, service='web')
|
|
||||||
app = fixture.TestApp(app)
|
|
||||||
|
|
||||||
app.get(url_for(controller='root', action='raise_exception'), status=404)
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_exception'
|
|
||||||
assert span.error == 0
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/raise_exception'
|
|
||||||
assert_span_http_status_code(span, 404)
|
|
||||||
assert span.get_tag(errors.ERROR_MSG) is None
|
|
||||||
assert span.get_tag(errors.ERROR_TYPE) is None
|
|
||||||
assert span.get_tag(errors.ERROR_STACK) is None
|
|
||||||
|
|
||||||
def test_success_200(self, query_string=''):
|
|
||||||
if query_string:
|
|
||||||
fqs = '?' + query_string
|
|
||||||
else:
|
|
||||||
fqs = ''
|
|
||||||
res = self.app.get(url_for(controller='root', action='index') + fqs)
|
|
||||||
assert res.status == 200
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.index'
|
|
||||||
assert_span_http_status_code(span, 200)
|
|
||||||
if config.pylons.trace_query_string:
|
|
||||||
assert span.meta.get(http.QUERY_STRING) == query_string
|
|
||||||
else:
|
|
||||||
assert http.QUERY_STRING not in span.meta
|
|
||||||
assert span.error == 0
|
|
||||||
|
|
||||||
def test_query_string(self):
|
|
||||||
return self.test_success_200('foo=bar')
|
|
||||||
|
|
||||||
def test_multi_query_string(self):
|
|
||||||
return self.test_success_200('foo=bar&foo=baz&x=y')
|
|
||||||
|
|
||||||
def test_query_string_trace(self):
|
|
||||||
with self.override_http_config('pylons', dict(trace_query_string=True)):
|
|
||||||
return self.test_success_200('foo=bar')
|
|
||||||
|
|
||||||
def test_multi_query_string_trace(self):
|
|
||||||
with self.override_http_config('pylons', dict(trace_query_string=True)):
|
|
||||||
return self.test_success_200('foo=bar&foo=baz&x=y')
|
|
||||||
|
|
||||||
def test_analytics_global_on_integration_default(self):
|
|
||||||
"""
|
|
||||||
When making a request
|
|
||||||
When an integration trace search is not event sample rate is not set and globally trace search is enabled
|
|
||||||
We expect the root span to have the appropriate tag
|
|
||||||
"""
|
|
||||||
with self.override_global_config(dict(analytics_enabled=True)):
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'))
|
|
||||||
self.assertEqual(res.status, 200)
|
|
||||||
|
|
||||||
self.assert_structure(
|
|
||||||
dict(name='pylons.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 1.0})
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_analytics_global_on_integration_on(self):
|
|
||||||
"""
|
|
||||||
When making a request
|
|
||||||
When an integration trace search is enabled and sample rate is set and globally trace search is enabled
|
|
||||||
We expect the root span to have the appropriate tag
|
|
||||||
"""
|
|
||||||
with self.override_global_config(dict(analytics_enabled=True)):
|
|
||||||
with self.override_config('pylons', dict(analytics_enabled=True, analytics_sample_rate=0.5)):
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'))
|
|
||||||
self.assertEqual(res.status, 200)
|
|
||||||
|
|
||||||
self.assert_structure(
|
|
||||||
dict(name='pylons.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5})
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_analytics_global_off_integration_default(self):
|
|
||||||
"""
|
|
||||||
When making a request
|
|
||||||
When an integration trace search is not set and sample rate is set and globally trace search is disabled
|
|
||||||
We expect the root span to not include tag
|
|
||||||
"""
|
|
||||||
with self.override_global_config(dict(analytics_enabled=False)):
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'))
|
|
||||||
self.assertEqual(res.status, 200)
|
|
||||||
|
|
||||||
root = self.get_root_span()
|
|
||||||
self.assertIsNone(root.get_metric(ANALYTICS_SAMPLE_RATE_KEY))
|
|
||||||
|
|
||||||
def test_analytics_global_off_integration_on(self):
|
|
||||||
"""
|
|
||||||
When making a request
|
|
||||||
When an integration trace search is enabled and sample rate is set and globally trace search is disabled
|
|
||||||
We expect the root span to have the appropriate tag
|
|
||||||
"""
|
|
||||||
with self.override_global_config(dict(analytics_enabled=False)):
|
|
||||||
with self.override_config('pylons', dict(analytics_enabled=True, analytics_sample_rate=0.5)):
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'))
|
|
||||||
self.assertEqual(res.status, 200)
|
|
||||||
|
|
||||||
self.assert_structure(
|
|
||||||
dict(name='pylons.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5})
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_template_render(self):
|
|
||||||
res = self.app.get(url_for(controller='root', action='render'))
|
|
||||||
assert res.status == 200
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 2
|
|
||||||
request = spans[0]
|
|
||||||
template = spans[1]
|
|
||||||
|
|
||||||
assert request.service == 'web'
|
|
||||||
assert request.resource == 'root.render'
|
|
||||||
assert_span_http_status_code(request, 200)
|
|
||||||
assert request.error == 0
|
|
||||||
|
|
||||||
assert template.service == 'web'
|
|
||||||
assert template.resource == 'pylons.render'
|
|
||||||
assert template.meta.get('template.name') == '/template.mako'
|
|
||||||
assert template.error == 0
|
|
||||||
|
|
||||||
def test_template_render_exception(self):
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
self.app.get(url_for(controller='root', action='render_exception'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 2
|
|
||||||
request = spans[0]
|
|
||||||
template = spans[1]
|
|
||||||
|
|
||||||
assert request.service == 'web'
|
|
||||||
assert request.resource == 'root.render_exception'
|
|
||||||
assert_span_http_status_code(request, 500)
|
|
||||||
assert request.error == 1
|
|
||||||
|
|
||||||
assert template.service == 'web'
|
|
||||||
assert template.resource == 'pylons.render'
|
|
||||||
assert template.meta.get('template.name') == '/exception.mako'
|
|
||||||
assert template.error == 1
|
|
||||||
assert template.get_tag('error.msg') == 'integer division or modulo by zero'
|
|
||||||
assert 'ZeroDivisionError: integer division or modulo by zero' in template.get_tag('error.stack')
|
|
||||||
|
|
||||||
def test_failure_500(self):
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
self.app.get(url_for(controller='root', action='raise_exception'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_exception'
|
|
||||||
assert span.error == 1
|
|
||||||
assert_span_http_status_code(span, 500)
|
|
||||||
assert span.get_tag('error.msg') == 'Ouch!'
|
|
||||||
assert span.get_tag(http.URL) == 'http://localhost:80/raise_exception'
|
|
||||||
assert 'Exception: Ouch!' in span.get_tag('error.stack')
|
|
||||||
|
|
||||||
def test_failure_500_with_wrong_code(self):
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
self.app.get(url_for(controller='root', action='raise_wrong_code'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_wrong_code'
|
|
||||||
assert span.error == 1
|
|
||||||
assert_span_http_status_code(span, 500)
|
|
||||||
assert span.meta.get(http.URL) == 'http://localhost:80/raise_wrong_code'
|
|
||||||
assert span.get_tag('error.msg') == 'Ouch!'
|
|
||||||
assert 'Exception: Ouch!' in span.get_tag('error.stack')
|
|
||||||
|
|
||||||
def test_failure_500_with_custom_code(self):
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
self.app.get(url_for(controller='root', action='raise_custom_code'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_custom_code'
|
|
||||||
assert span.error == 1
|
|
||||||
assert_span_http_status_code(span, 512)
|
|
||||||
assert span.meta.get(http.URL) == 'http://localhost:80/raise_custom_code'
|
|
||||||
assert span.get_tag('error.msg') == 'Ouch!'
|
|
||||||
assert 'Exception: Ouch!' in span.get_tag('error.stack')
|
|
||||||
|
|
||||||
def test_failure_500_with_code_method(self):
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
self.app.get(url_for(controller='root', action='raise_code_method'))
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.service == 'web'
|
|
||||||
assert span.resource == 'root.raise_code_method'
|
|
||||||
assert span.error == 1
|
|
||||||
assert_span_http_status_code(span, 500)
|
|
||||||
assert span.meta.get(http.URL) == 'http://localhost:80/raise_code_method'
|
|
||||||
assert span.get_tag('error.msg') == 'Ouch!'
|
|
||||||
|
|
||||||
def test_distributed_tracing_default(self):
|
|
||||||
# ensure by default, distributed tracing is not enabled
|
|
||||||
headers = {
|
|
||||||
'x-datadog-trace-id': '100',
|
|
||||||
'x-datadog-parent-id': '42',
|
|
||||||
'x-datadog-sampling-priority': '2',
|
|
||||||
}
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'), headers=headers)
|
|
||||||
assert res.status == 200
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.trace_id == 100
|
|
||||||
assert span.parent_id == 42
|
|
||||||
assert span.get_metric(SAMPLING_PRIORITY_KEY) == 2
|
|
||||||
|
|
||||||
def test_distributed_tracing_disabled(self):
|
|
||||||
# ensure distributed tracing propagator is working
|
|
||||||
middleware = self.app.app
|
|
||||||
middleware._distributed_tracing = False
|
|
||||||
headers = {
|
|
||||||
'x-datadog-trace-id': '100',
|
|
||||||
'x-datadog-parent-id': '42',
|
|
||||||
'x-datadog-sampling-priority': '2',
|
|
||||||
}
|
|
||||||
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'), headers=headers)
|
|
||||||
assert res.status == 200
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 1
|
|
||||||
span = spans[0]
|
|
||||||
|
|
||||||
assert span.trace_id != 100
|
|
||||||
assert span.parent_id != 42
|
|
||||||
assert span.get_metric(SAMPLING_PRIORITY_KEY) != 2
|
|
||||||
|
|
||||||
def test_success_200_ot(self):
|
|
||||||
"""OpenTracing version of test_success_200."""
|
|
||||||
ot_tracer = init_tracer('pylons_svc', self.tracer)
|
|
||||||
|
|
||||||
with ot_tracer.start_active_span('pylons_get'):
|
|
||||||
res = self.app.get(url_for(controller='root', action='index'))
|
|
||||||
assert res.status == 200
|
|
||||||
|
|
||||||
spans = self.tracer.writer.pop()
|
|
||||||
assert spans, spans
|
|
||||||
assert len(spans) == 2
|
|
||||||
ot_span, dd_span = spans
|
|
||||||
|
|
||||||
# confirm the parenting
|
|
||||||
assert ot_span.parent_id is None
|
|
||||||
assert dd_span.parent_id == ot_span.span_id
|
|
||||||
|
|
||||||
assert ot_span.name == 'pylons_get'
|
|
||||||
assert ot_span.service == 'pylons_svc'
|
|
||||||
|
|
||||||
assert dd_span.service == 'web'
|
|
||||||
assert dd_span.resource == 'root.index'
|
|
||||||
assert_span_http_status_code(dd_span, 200)
|
|
||||||
assert dd_span.meta.get(http.URL) == 'http://localhost:80/'
|
|
||||||
assert dd_span.error == 0
|
|
204
tox.ini
204
tox.ini
@ -20,12 +20,12 @@ envlist =
|
|||||||
flake8
|
flake8
|
||||||
black
|
black
|
||||||
wait
|
wait
|
||||||
{py27,py34,py35,py36,py37}-tracer
|
{py34,py35,py36,py37}-tracer
|
||||||
{py27,py34,py35,py36,py37}-internal
|
{py34,py35,py36,py37}-internal
|
||||||
{py27,py34,py35,py36,py37}-integration
|
{py34,py35,py36,py37}-integration
|
||||||
{py27,py34,py35,py36,py37}-ddtracerun
|
{py34,py35,py36,py37}-ddtracerun
|
||||||
{py27,py34,py35,py36,py37}-test_utils
|
{py34,py35,py36,py37}-test_utils
|
||||||
{py27,py34,py35,py36,py37}-test_logging
|
{py34,py35,py36,py37}-test_logging
|
||||||
# Integrations environments
|
# Integrations environments
|
||||||
aiobotocore_contrib-py34-aiobotocore{02,03,04}
|
aiobotocore_contrib-py34-aiobotocore{02,03,04}
|
||||||
aiobotocore_contrib-{py35,py36}-aiobotocore{02,03,04,05,07,08,09,010}
|
aiobotocore_contrib-{py35,py36}-aiobotocore{02,03,04,05,07,08,09,010}
|
||||||
@ -37,70 +37,63 @@ envlist =
|
|||||||
aiohttp_contrib-{py35,py36,py37}-aiohttp{30,31,32,33,34,35}-aiohttp_jinja{015}-yarl10
|
aiohttp_contrib-{py35,py36,py37}-aiohttp{30,31,32,33,34,35}-aiohttp_jinja{015}-yarl10
|
||||||
aiopg_contrib-{py34,py35,py36}-aiopg{012,015}
|
aiopg_contrib-{py34,py35,py36}-aiopg{012,015}
|
||||||
aiopg_contrib-py37-aiopg015
|
aiopg_contrib-py37-aiopg015
|
||||||
algoliasearch_contrib-{py27,py34,py35,py36,py37}-algoliasearch{1,2}
|
algoliasearch_contrib-{py34,py35,py36,py37}-algoliasearch{1,2}
|
||||||
asyncio_contrib-{py34,py35,py36,py37}
|
asyncio_contrib-{py34,py35,py36,py37}
|
||||||
# boto needs moto<1 and moto<1 does not support Python >= 3.7
|
# boto needs moto<1 and moto<1 does not support Python >= 3.7
|
||||||
boto_contrib-{py27,py34,py35,py36}-boto
|
boto_contrib-{py34,py35,py36}-boto
|
||||||
botocore_contrib-{py27,py34,py35,py36,py37}-botocore
|
botocore_contrib-{py34,py35,py36,py37}-botocore
|
||||||
bottle_contrib{,_autopatch}-{py27,py34,py35,py36,py37}-bottle{11,12}-webtest
|
bottle_contrib{,_autopatch}-{py34,py35,py36,py37}-bottle{11,12}-webtest
|
||||||
cassandra_contrib-{py27,py34,py35,py36,py37}-cassandra{35,36,37,38,315}
|
cassandra_contrib-{py34,py35,py36,py37}-cassandra{35,36,37,38,315}
|
||||||
# Non-4.x celery should be able to use the older redis lib, since it locks to an older kombu
|
# Non-4.x celery should be able to use the older redis lib, since it locks to an older kombu
|
||||||
celery_contrib-{py27,py34,py35,py36}-celery{31}-redis{210}
|
celery_contrib-{py34,py35,py36}-celery{31}-redis{210}
|
||||||
# 4.x celery bumps kombu to 4.4+, which requires redis 3.2 or later, this tests against
|
# 4.x celery bumps kombu to 4.4+, which requires redis 3.2 or later, this tests against
|
||||||
# older redis with an older kombu, and newer kombu/newer redis.
|
# older redis with an older kombu, and newer kombu/newer redis.
|
||||||
# https://github.com/celery/kombu/blob/3e60e6503a77b9b1a987cf7954659929abac9bac/Changelog#L35
|
# https://github.com/celery/kombu/blob/3e60e6503a77b9b1a987cf7954659929abac9bac/Changelog#L35
|
||||||
celery_contrib-{py27,py34,py35,py36}-celery{40,41}-{redis210-kombu43,redis320-kombu44}
|
celery_contrib-{py34,py35,py36}-celery{40,41}-{redis210-kombu43,redis320-kombu44}
|
||||||
# Celery 4.2 is now limited to Kombu 4.3
|
# Celery 4.2 is now limited to Kombu 4.3
|
||||||
# https://github.com/celery/celery/commit/1571d414461f01ae55be63a03e2adaa94dbcb15d
|
# https://github.com/celery/celery/commit/1571d414461f01ae55be63a03e2adaa94dbcb15d
|
||||||
celery_contrib-{py27,py34,py35,py36}-celery42-redis210-kombu43
|
celery_contrib-{py34,py35,py36}-celery42-redis210-kombu43
|
||||||
# Celery 4.3 wants Kombu >= 4.4 and Redis >= 3.2
|
# Celery 4.3 wants Kombu >= 4.4 and Redis >= 3.2
|
||||||
# Python 3.7 needs Celery 4.3
|
# Python 3.7 needs Celery 4.3
|
||||||
celery_contrib-{py27,py34,py35,py36,py37}-celery43-redis320-kombu44
|
celery_contrib-{py34,py35,py36,py37}-celery43-redis320-kombu44
|
||||||
consul_contrib-py{27,34,35,36,37}-consul{07,10,11}
|
consul_contrib-py{34,35,36,37}-consul{07,10,11}
|
||||||
dbapi_contrib-{py27,py34,py35,py36}
|
dbapi_contrib-{py34,py35,py36}
|
||||||
django_contrib{,_autopatch}-{py27,py34,py35,py36}-django{18,111}-djangopylibmc06-djangoredis45-pylibmc-redis{210}-memcached
|
django_contrib{,_autopatch}-{py34,py35,py36}-django{18,111}-djangopylibmc06-djangoredis45-pylibmc-redis{210}-memcached
|
||||||
django_contrib{,_autopatch}-{py34,py35,py36}-django{200}-djangopylibmc06-djangoredis45-pylibmc-redis{210}-memcached
|
django_contrib{,_autopatch}-{py34,py35,py36}-django{200}-djangopylibmc06-djangoredis45-pylibmc-redis{210}-memcached
|
||||||
django_drf_contrib-{py27,py34,py35,py36}-django{111}-djangorestframework{34,37,38}
|
django_drf_contrib-{py34,py35,py36}-django{111}-djangorestframework{34,37,38}
|
||||||
django_drf_contrib-{py34,py35,py36}-django{200}-djangorestframework{37,38}
|
django_drf_contrib-{py34,py35,py36}-django{200}-djangorestframework{37,38}
|
||||||
dogpile_contrib-{py27,py35,py36,py37}-dogpilecache{06,07,08,latest}
|
dogpile_contrib-{py35,py36,py37}-dogpilecache{06,07,08,latest}
|
||||||
elasticsearch_contrib-{py27,py34,py35,py36}-elasticsearch{16,17,18,23,24,51,52,53,54,63,64}
|
elasticsearch_contrib-{py34,py35,py36}-elasticsearch{16,17,18,23,24,51,52,53,54,63,64}
|
||||||
elasticsearch_contrib-{py27,py34,py35,py36}-elasticsearch1{100}
|
elasticsearch_contrib-{py34,py35,py36}-elasticsearch1{100}
|
||||||
elasticsearch_contrib-{py27,py34,py35,py36}-elasticsearch2{50}
|
elasticsearch_contrib-{py34,py35,py36}-elasticsearch2{50}
|
||||||
elasticsearch_contrib-{py27,py34,py35,py36}-elasticsearch5{50}
|
elasticsearch_contrib-{py34,py35,py36}-elasticsearch5{50}
|
||||||
elasticsearch_contrib-{py27,py34,py35,py36}-elasticsearch6{40}
|
elasticsearch_contrib-{py34,py35,py36}-elasticsearch6{40}
|
||||||
falcon_contrib{,_autopatch}-{py27,py34,py35,py36}-falcon{10,11,12,13,14}
|
falcon_contrib{,_autopatch}-{py34,py35,py36}-falcon{10,11,12,13,14}
|
||||||
flask_contrib{,_autopatch}-{py27,py34,py35,py36}-flask{010,011,012,10}-blinker
|
flask_contrib{,_autopatch}-{py34,py35,py36}-flask{010,011,012,10}-blinker
|
||||||
# Flask <=0.9 does not support Python 3
|
flask_cache_contrib{,_autopatch}-{py34,py35,py36,py37}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker
|
||||||
flask_contrib{,_autopatch}-{py27}-flask{09}-blinker
|
|
||||||
flask_cache_contrib{,_autopatch}-{py27,py34,py35,py36,py37}-flask{010,011,012}-flaskcache{013}-memcached-redis{210}-blinker
|
|
||||||
flask_cache_contrib{,_autopatch}-{py27}-flask{010,011}-flaskcache{012}-memcached-redis{210}-blinker
|
|
||||||
futures_contrib-{py27}-futures{30,31,32}
|
|
||||||
futures_contrib-{py34,py35,py36,py37}
|
futures_contrib-{py34,py35,py36,py37}
|
||||||
gevent_contrib-{py27,py34,py35,py36}-gevent{11,12,13}
|
gevent_contrib-{py34,py35,py36}-gevent{11,12,13}
|
||||||
gevent_contrib-py37-gevent{13,14}
|
gevent_contrib-py37-gevent{13,14}
|
||||||
# gevent 1.0 is not python 3 compatible
|
grpc_contrib-{py34,py35,py36,py37}-grpc{112,113,114,115,116,117,118,119,120,121,122}
|
||||||
gevent_contrib-{py27}-gevent{10}
|
httplib_contrib-{py34,py35,py36,py37}
|
||||||
grpc_contrib-{py27,py34,py35,py36,py37}-grpc{112,113,114,115,116,117,118,119,120,121,122}
|
jinja2_contrib-{py34,py35,py36,py37}-jinja{27,28,29,210}
|
||||||
httplib_contrib-{py27,py34,py35,py36,py37}
|
mako_contrib-{py34,py35,py36,py37}-mako{010,100}
|
||||||
jinja2_contrib-{py27,py34,py35,py36,py37}-jinja{27,28,29,210}
|
|
||||||
mako_contrib-{py27,py34,py35,py36,py37}-mako{010,100}
|
|
||||||
molten_contrib-py{36,37}-molten{070,072}
|
molten_contrib-py{36,37}-molten{070,072}
|
||||||
mongoengine_contrib-{py27,py34,py35,py36,py37}-mongoengine{015,016,017,018,latest}-pymongo{latest}
|
mongoengine_contrib-{py34,py35,py36,py37}-mongoengine{015,016,017,018,latest}-pymongo{latest}
|
||||||
mysql_contrib-{py27,py34,py35,py36,py37}-mysqlconnector
|
mysql_contrib-{py34,py35,py36,py37}-mysqlconnector
|
||||||
mysqldb_contrib-{py27}-mysqldb{12}
|
mysqldb_contrib-{py27}-mysqldb{12}
|
||||||
mysqldb_contrib-{py27,py34,py35,py36,py37}-mysqlclient{13}
|
mysqldb_contrib-{py34,py35,py36,py37}-mysqlclient{13}
|
||||||
psycopg_contrib-{py27,py34,py35,py36}-psycopg2{24,25,26,27,28}
|
psycopg_contrib-{py34,py35,py36}-psycopg2{24,25,26,27,28}
|
||||||
psycopg_contrib-py37-psycopg2{27,28}
|
psycopg_contrib-py37-psycopg2{27,28}
|
||||||
pylibmc_contrib-{py27,py34,py35,py36,py37}-pylibmc{140,150}
|
pylibmc_contrib-{py34,py35,py36,py37}-pylibmc{140,150}
|
||||||
pylons_contrib-{py27}-pylons{096,097,010,10}
|
pymemcache_contrib{,_autopatch}-{py34,py35,py36,py37}-pymemcache{130,140}
|
||||||
pymemcache_contrib{,_autopatch}-{py27,py34,py35,py36,py37}-pymemcache{130,140}
|
pymongo_contrib-{py34,py35,py36,py37}-pymongo{30,31,32,33,34,35,36,37,38,39,latest}-mongoengine{latest}
|
||||||
pymongo_contrib-{py27,py34,py35,py36,py37}-pymongo{30,31,32,33,34,35,36,37,38,39,latest}-mongoengine{latest}
|
pymysql_contrib-{py34,py35,py36,py37}-pymysql{07,08,09}
|
||||||
pymysql_contrib-{py27,py34,py35,py36,py37}-pymysql{07,08,09}
|
pyramid_contrib{,_autopatch}-{py34,py35,py36,py37}-pyramid{17,18,19}-webtest
|
||||||
pyramid_contrib{,_autopatch}-{py27,py34,py35,py36,py37}-pyramid{17,18,19}-webtest
|
redis_contrib-{py34,py35,py36,py37}-redis{26,27,28,29,210,300}
|
||||||
redis_contrib-{py27,py34,py35,py36,py37}-redis{26,27,28,29,210,300}
|
rediscluster_contrib-{py34,py35,py36,py37}-rediscluster{135,136}-redis210
|
||||||
rediscluster_contrib-{py27,py34,py35,py36,py37}-rediscluster{135,136}-redis210
|
requests_contrib{,_autopatch}-{py34,py35,py36,py37}-requests{208,209,210,211,212,213,219}
|
||||||
requests_contrib{,_autopatch}-{py27,py34,py35,py36,py37}-requests{208,209,210,211,212,213,219}
|
kombu_contrib-{py34,py35,py36}-kombu{40,41,42}
|
||||||
kombu_contrib-{py27,py34,py35,py36}-kombu{40,41,42}
|
|
||||||
# Python 3.7 needs Kombu >= 4.2
|
# Python 3.7 needs Kombu >= 4.2
|
||||||
kombu_contrib-py37-kombu42
|
kombu_contrib-py37-kombu42
|
||||||
# python 3.6 requests + gevent regression test
|
# python 3.6 requests + gevent regression test
|
||||||
@ -108,22 +101,20 @@ envlist =
|
|||||||
# https://github.com/gevent/gevent/issues/903
|
# https://github.com/gevent/gevent/issues/903
|
||||||
requests_gevent_contrib-{py36}-requests{208,209,210,211,212,213,219}-gevent{12,13}
|
requests_gevent_contrib-{py36}-requests{208,209,210,211,212,213,219}-gevent{12,13}
|
||||||
requests_gevent_contrib-py37-requests{208,209,210,211,212,213,219}-gevent13
|
requests_gevent_contrib-py37-requests{208,209,210,211,212,213,219}-gevent13
|
||||||
sqlalchemy_contrib-{py27,py34,py35,py36,py37}-sqlalchemy{10,11,12}-psycopg228-mysqlconnector
|
sqlalchemy_contrib-{py34,py35,py36,py37}-sqlalchemy{10,11,12}-psycopg228-mysqlconnector
|
||||||
sqlite3_contrib-{py27,py34,py35,py36,py37}-sqlite3
|
sqlite3_contrib-{py34,py35,py36,py37}-sqlite3
|
||||||
tornado_contrib-{py27,py34,py35,py36,py37}-tornado{40,41,42,43,44,45}
|
tornado_contrib-{py34,py35,py36,py37}-tornado{40,41,42,43,44,45}
|
||||||
tornado_contrib-{py37}-tornado{50,51,60}
|
tornado_contrib-{py37}-tornado{50,51,60}
|
||||||
tornado_contrib-{py27}-tornado{40,41,42,43,44,45}-futures{30,31,32}
|
vertica_contrib-{py34,py35,py36,py37}-vertica{060,070}
|
||||||
vertica_contrib-{py27,py34,py35,py36,py37}-vertica{060,070}
|
|
||||||
# Opentracer
|
# Opentracer
|
||||||
{py27,py34,py35,py36,py37}-opentracer
|
{py34,py35,py36,py37}-opentracer
|
||||||
{py34,py35,py36,py37}-opentracer_asyncio
|
{py34,py35,py36,py37}-opentracer_asyncio
|
||||||
{py34,py35,py36,py37}-opentracer_tornado-tornado{40,41,42,43,44}
|
{py34,py35,py36,py37}-opentracer_tornado-tornado{40,41,42,43,44}
|
||||||
{py27}-opentracer_gevent-gevent{10}
|
{py34,py35,py36}-opentracer_gevent-gevent{11,12}
|
||||||
{py27,py34,py35,py36}-opentracer_gevent-gevent{11,12}
|
|
||||||
py37-opentracer_gevent-gevent{13,14}
|
py37-opentracer_gevent-gevent{13,14}
|
||||||
# Unit tests: pytest based test suite that do not require any additional dependency
|
# Unit tests: pytest based test suite that do not require any additional dependency
|
||||||
unit_tests-{py27,py34,py35,py36,py37}
|
unit_tests-{py34,py35,py36,py37}
|
||||||
benchmarks-{py27,py34,py35,py36,py37}
|
benchmarks-{py34,py35,py36,py37}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
# Always re-run `setup.py develop` to ensure the proper C-extension .so files are created
|
# Always re-run `setup.py develop` to ensure the proper C-extension .so files are created
|
||||||
@ -133,7 +124,6 @@ envlist =
|
|||||||
commands_pre={envpython} {toxinidir}/setup.py develop
|
commands_pre={envpython} {toxinidir}/setup.py develop
|
||||||
usedevelop = True
|
usedevelop = True
|
||||||
basepython =
|
basepython =
|
||||||
py27: python2.7
|
|
||||||
py34: python3.4
|
py34: python3.4
|
||||||
py35: python3.5
|
py35: python3.5
|
||||||
py36: python3.6
|
py36: python3.6
|
||||||
@ -153,8 +143,6 @@ deps =
|
|||||||
# https://github.com/aio-libs/aiohttp/issues/2662
|
# https://github.com/aio-libs/aiohttp/issues/2662
|
||||||
yarl: yarl==0.18.0
|
yarl: yarl==0.18.0
|
||||||
yarl10: yarl>=1.0,<1.1
|
yarl10: yarl>=1.0,<1.1
|
||||||
# backports
|
|
||||||
py27: enum34
|
|
||||||
# integrations
|
# integrations
|
||||||
aiobotocore010: aiobotocore>=0.10,<0.11
|
aiobotocore010: aiobotocore>=0.10,<0.11
|
||||||
aiobotocore09: aiobotocore>=0.9,<0.10
|
aiobotocore09: aiobotocore>=0.9,<0.10
|
||||||
@ -246,7 +234,6 @@ deps =
|
|||||||
falcon12: falcon>=1.2,<1.3
|
falcon12: falcon>=1.2,<1.3
|
||||||
falcon13: falcon>=1.3,<1.4
|
falcon13: falcon>=1.3,<1.4
|
||||||
falcon14: falcon>=1.4,<1.5
|
falcon14: falcon>=1.4,<1.5
|
||||||
flask09: flask>=0.9,<0.10
|
|
||||||
flask010: flask>=0.10,<0.11
|
flask010: flask>=0.10,<0.11
|
||||||
flask011: flask>=0.11,<0.12
|
flask011: flask>=0.11,<0.12
|
||||||
flask012: flask>=0.12,<0.13
|
flask012: flask>=0.12,<0.13
|
||||||
@ -257,7 +244,6 @@ deps =
|
|||||||
futures30: futures>=3.0,<3.1
|
futures30: futures>=3.0,<3.1
|
||||||
futures31: futures>=3.1,<3.2
|
futures31: futures>=3.1,<3.2
|
||||||
futures32: futures>=3.2,<3.3
|
futures32: futures>=3.2,<3.3
|
||||||
gevent10: gevent>=1.0,<1.1
|
|
||||||
gevent11: gevent>=1.1,<1.2
|
gevent11: gevent>=1.1,<1.2
|
||||||
gevent12: gevent>=1.2,<1.3
|
gevent12: gevent>=1.2,<1.3
|
||||||
gevent13: gevent>=1.3,<1.4
|
gevent13: gevent>=1.3,<1.4
|
||||||
@ -301,14 +287,6 @@ deps =
|
|||||||
mysqlconnector: mysql-connector-python!=8.0.18
|
mysqlconnector: mysql-connector-python!=8.0.18
|
||||||
mysqldb12: mysql-python>=1.2,<1.3
|
mysqldb12: mysql-python>=1.2,<1.3
|
||||||
mysqlclient13: mysqlclient>=1.3,<1.4
|
mysqlclient13: mysqlclient>=1.3,<1.4
|
||||||
# webob is required for Pylons < 1.0
|
|
||||||
pylons096: pylons>=0.9.6,<0.9.7
|
|
||||||
pylons096: webob<1.1
|
|
||||||
pylons097: pylons>=0.9.7,<0.9.8
|
|
||||||
pylons097: webob<1.1
|
|
||||||
pylons010: pylons>=0.10,<0.11
|
|
||||||
pylons010: webob<1.1
|
|
||||||
pylons10: pylons>=1.0,<1.1
|
|
||||||
pylibmc: pylibmc
|
pylibmc: pylibmc
|
||||||
pylibmc140: pylibmc>=1.4.0,<1.5.0
|
pylibmc140: pylibmc>=1.4.0,<1.5.0
|
||||||
pylibmc150: pylibmc>=1.5.0,<1.6.0
|
pylibmc150: pylibmc>=1.5.0,<1.6.0
|
||||||
@ -426,7 +404,6 @@ commands =
|
|||||||
mysqldb_contrib: pytest {posargs} tests/contrib/mysqldb
|
mysqldb_contrib: pytest {posargs} tests/contrib/mysqldb
|
||||||
psycopg_contrib: pytest {posargs} tests/contrib/psycopg
|
psycopg_contrib: pytest {posargs} tests/contrib/psycopg
|
||||||
pylibmc_contrib: pytest {posargs} tests/contrib/pylibmc
|
pylibmc_contrib: pytest {posargs} tests/contrib/pylibmc
|
||||||
pylons_contrib: pytest {posargs} tests/contrib/pylons
|
|
||||||
pymemcache_contrib: pytest {posargs} --ignore="tests/contrib/pymemcache/autopatch" tests/contrib/pymemcache/
|
pymemcache_contrib: pytest {posargs} --ignore="tests/contrib/pymemcache/autopatch" tests/contrib/pymemcache/
|
||||||
pymemcache_contrib_autopatch: python tests/ddtrace_run.py pytest {posargs} tests/contrib/pymemcache/autopatch/
|
pymemcache_contrib_autopatch: python tests/ddtrace_run.py pytest {posargs} tests/contrib/pymemcache/autopatch/
|
||||||
pymongo_contrib: pytest {posargs} tests/contrib/pymongo
|
pymongo_contrib: pytest {posargs} tests/contrib/pymongo
|
||||||
@ -487,22 +464,12 @@ basepython=python3.7
|
|||||||
# same job will cause problem for tests that use ddtrace-run
|
# same job will cause problem for tests that use ddtrace-run
|
||||||
[celery_contrib]
|
[celery_contrib]
|
||||||
usedevelop = False
|
usedevelop = False
|
||||||
[testenv:celery_contrib-py27-celery31-redis210]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py34-celery31-redis210]
|
[testenv:celery_contrib-py34-celery31-redis210]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py35-celery31-redis210]
|
[testenv:celery_contrib-py35-celery31-redis210]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py36-celery31-redis210]
|
[testenv:celery_contrib-py36-celery31-redis210]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py27-celery40-redis210-kombu43]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py27-celery40-redis320-kombu44]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py27-celery41-redis210-kombu43]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py27-celery41-redis320-kombu44]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py34-celery40-redis210-kombu43]
|
[testenv:celery_contrib-py34-celery40-redis210-kombu43]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py34-celery40-redis320-kombu44]
|
[testenv:celery_contrib-py34-celery40-redis320-kombu44]
|
||||||
@ -527,16 +494,12 @@ usedevelop = {[celery_contrib]usedevelop}
|
|||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py36-celery41-redis320-kombu44]
|
[testenv:celery_contrib-py36-celery41-redis320-kombu44]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py27-celery42-redis210-kombu43]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py34-celery42-redis210-kombu43]
|
[testenv:celery_contrib-py34-celery42-redis210-kombu43]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py35-celery42-redis210-kombu43]
|
[testenv:celery_contrib-py35-celery42-redis210-kombu43]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py36-celery42-redis210-kombu43]
|
[testenv:celery_contrib-py36-celery42-redis210-kombu43]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py27-celery43-redis320-kombu44]
|
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
|
||||||
[testenv:celery_contrib-py34-celery43-redis320-kombu44]
|
[testenv:celery_contrib-py34-celery43-redis320-kombu44]
|
||||||
usedevelop = {[celery_contrib]usedevelop}
|
usedevelop = {[celery_contrib]usedevelop}
|
||||||
[testenv:celery_contrib-py35-celery43-redis320-kombu44]
|
[testenv:celery_contrib-py35-celery43-redis320-kombu44]
|
||||||
@ -549,21 +512,6 @@ usedevelop = {[celery_contrib]usedevelop}
|
|||||||
[falcon_autopatch]
|
[falcon_autopatch]
|
||||||
setenv =
|
setenv =
|
||||||
DATADOG_SERVICE_NAME=my-falcon
|
DATADOG_SERVICE_NAME=my-falcon
|
||||||
[testenv:falcon_contrib_autopatch-py27-falcon10]
|
|
||||||
setenv =
|
|
||||||
{[falcon_autopatch]setenv}
|
|
||||||
[testenv:falcon_contrib_autopatch-py27-falcon11]
|
|
||||||
setenv =
|
|
||||||
{[falcon_autopatch]setenv}
|
|
||||||
[testenv:falcon_contrib_autopatch-py27-falcon12]
|
|
||||||
setenv =
|
|
||||||
{[falcon_autopatch]setenv}
|
|
||||||
[testenv:falcon_contrib_autopatch-py27-falcon13]
|
|
||||||
setenv =
|
|
||||||
{[falcon_autopatch]setenv}
|
|
||||||
[testenv:falcon_contrib_autopatch-py27-falcon14]
|
|
||||||
setenv =
|
|
||||||
{[falcon_autopatch]setenv}
|
|
||||||
[testenv:falcon_contrib_autopatch-py34-falcon10]
|
[testenv:falcon_contrib_autopatch-py34-falcon10]
|
||||||
setenv =
|
setenv =
|
||||||
{[falcon_autopatch]setenv}
|
{[falcon_autopatch]setenv}
|
||||||
@ -630,16 +578,6 @@ setenv =
|
|||||||
setenv =
|
setenv =
|
||||||
DATADOG_SERVICE_NAME = foobar
|
DATADOG_SERVICE_NAME = foobar
|
||||||
DATADOG_PYRAMID_DISTRIBUTED_TRACING = True
|
DATADOG_PYRAMID_DISTRIBUTED_TRACING = True
|
||||||
[testenv:pyramid_contrib_autopatch-py27-pyramid17-webtest]
|
|
||||||
setenv =
|
|
||||||
{[pyramid_autopatch]setenv}
|
|
||||||
|
|
||||||
[testenv:pyramid_contrib_autopatch-py27-pyramid18-webtest]
|
|
||||||
setenv =
|
|
||||||
{[pyramid_autopatch]setenv}
|
|
||||||
[testenv:pyramid_contrib_autopatch-py27-pyramid19-webtest]
|
|
||||||
setenv =
|
|
||||||
{[pyramid_autopatch]setenv}
|
|
||||||
[testenv:pyramid_contrib_autopatch-py34-pyramid17-webtest]
|
[testenv:pyramid_contrib_autopatch-py34-pyramid17-webtest]
|
||||||
setenv =
|
setenv =
|
||||||
{[pyramid_autopatch]setenv}
|
{[pyramid_autopatch]setenv}
|
||||||
@ -682,18 +620,6 @@ setenv =
|
|||||||
setenv =
|
setenv =
|
||||||
DATADOG_SERVICE_NAME = test.flask.service
|
DATADOG_SERVICE_NAME = test.flask.service
|
||||||
DATADOG_PATCH_MODULES = jinja2:false
|
DATADOG_PATCH_MODULES = jinja2:false
|
||||||
[testenv:flask_contrib_autopatch-py27-flask010-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask011-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask012-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask10-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py34-flask010-blinker]
|
[testenv:flask_contrib_autopatch-py34-flask010-blinker]
|
||||||
setenv =
|
setenv =
|
||||||
{[flask_autopatch]setenv}
|
{[flask_autopatch]setenv}
|
||||||
@ -740,15 +666,6 @@ setenv =
|
|||||||
setenv =
|
setenv =
|
||||||
{[flask_autopatch]setenv}
|
{[flask_autopatch]setenv}
|
||||||
[testenv:flask_contrib_autopatch-py37-flask10-blinker]
|
[testenv:flask_contrib_autopatch-py37-flask10-blinker]
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask010-flaskcache013-memcached-redis210-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask011-flaskcache013-memcached-redis210-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask012-flaskcache013-memcached-redis210-blinker]
|
|
||||||
setenv =
|
setenv =
|
||||||
{[flask_autopatch]setenv}
|
{[flask_autopatch]setenv}
|
||||||
[testenv:flask_contrib_autopatch-py34-flask010-flaskcache013-memcached-redis210-blinker]
|
[testenv:flask_contrib_autopatch-py34-flask010-flaskcache013-memcached-redis210-blinker]
|
||||||
@ -787,20 +704,10 @@ setenv =
|
|||||||
[testenv:flask_contrib_autopatch-py37-flask012-flaskcache013-memcached-redis210-blinker]
|
[testenv:flask_contrib_autopatch-py37-flask012-flaskcache013-memcached-redis210-blinker]
|
||||||
setenv =
|
setenv =
|
||||||
{[flask_autopatch]setenv}
|
{[flask_autopatch]setenv}
|
||||||
[testenv:flask_contrib_autopatch-py27-flask010-flaskcache012-memcached-redis210-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
[testenv:flask_contrib_autopatch-py27-flask011-flaskcache012-memcached-redis210-blinker]
|
|
||||||
setenv =
|
|
||||||
{[flask_autopatch]setenv}
|
|
||||||
|
|
||||||
|
|
||||||
[bottle_autopatch]
|
[bottle_autopatch]
|
||||||
setenv =
|
setenv =
|
||||||
DATADOG_SERVICE_NAME = bottle-app
|
DATADOG_SERVICE_NAME = bottle-app
|
||||||
[testenv:bottle_contrib_autopatch-py27-bottle11-webtest]
|
|
||||||
setenv =
|
|
||||||
{[bottle_autopatch]setenv}
|
|
||||||
[testenv:bottle_contrib_autopatch-py34-bottle11-webtest]
|
[testenv:bottle_contrib_autopatch-py34-bottle11-webtest]
|
||||||
setenv =
|
setenv =
|
||||||
{[bottle_autopatch]setenv}
|
{[bottle_autopatch]setenv}
|
||||||
@ -811,9 +718,6 @@ setenv =
|
|||||||
setenv =
|
setenv =
|
||||||
{[bottle_autopatch]setenv}
|
{[bottle_autopatch]setenv}
|
||||||
[testenv:bottle_contrib_autopatch-py37-bottle11-webtest]
|
[testenv:bottle_contrib_autopatch-py37-bottle11-webtest]
|
||||||
setenv =
|
|
||||||
{[bottle_autopatch]setenv}
|
|
||||||
[testenv:bottle_contrib_autopatch-py27-bottle12-webtest]
|
|
||||||
setenv =
|
setenv =
|
||||||
{[bottle_autopatch]setenv}
|
{[bottle_autopatch]setenv}
|
||||||
[testenv:bottle_contrib_autopatch-py34-bottle12-webtest]
|
[testenv:bottle_contrib_autopatch-py34-bottle12-webtest]
|
||||||
|
Reference in New Issue
Block a user