85 lines
3.2 KiB
Python
85 lines
3.2 KiB
Python
import os
|
|
|
|
from .trace import trace_pyramid, DD_TWEEN_NAME
|
|
from .constants import (
|
|
SETTINGS_SERVICE, SETTINGS_DISTRIBUTED_TRACING,
|
|
SETTINGS_ANALYTICS_ENABLED, SETTINGS_ANALYTICS_SAMPLE_RATE,
|
|
)
|
|
from ...utils.formats import asbool, get_env
|
|
|
|
import pyramid.config
|
|
from pyramid.path import caller_package
|
|
|
|
from ddtrace.vendor import wrapt
|
|
|
|
DD_PATCH = '_datadog_patch'
|
|
|
|
|
|
def patch():
|
|
"""
|
|
Patch pyramid.config.Configurator
|
|
"""
|
|
if getattr(pyramid.config, DD_PATCH, False):
|
|
return
|
|
|
|
setattr(pyramid.config, DD_PATCH, True)
|
|
_w = wrapt.wrap_function_wrapper
|
|
_w('pyramid.config', 'Configurator.__init__', traced_init)
|
|
|
|
|
|
def traced_init(wrapped, instance, args, kwargs):
|
|
settings = kwargs.pop('settings', {})
|
|
service = os.environ.get('DATADOG_SERVICE_NAME') or 'pyramid'
|
|
distributed_tracing = asbool(get_env('pyramid', 'distributed_tracing', True))
|
|
# DEV: integration-specific analytics flag can be not set but still enabled
|
|
# globally for web frameworks
|
|
analytics_enabled = get_env('pyramid', 'analytics_enabled')
|
|
if analytics_enabled is not None:
|
|
analytics_enabled = asbool(analytics_enabled)
|
|
analytics_sample_rate = get_env('pyramid', 'analytics_sample_rate', True)
|
|
trace_settings = {
|
|
SETTINGS_SERVICE: service,
|
|
SETTINGS_DISTRIBUTED_TRACING: distributed_tracing,
|
|
SETTINGS_ANALYTICS_ENABLED: analytics_enabled,
|
|
SETTINGS_ANALYTICS_SAMPLE_RATE: analytics_sample_rate,
|
|
}
|
|
# Update over top of the defaults
|
|
# DEV: If we did `settings.update(trace_settings)` then we would only ever
|
|
# have the default values.
|
|
trace_settings.update(settings)
|
|
# If the tweens are explicitly set with 'pyramid.tweens', we need to
|
|
# explicitly set our tween too since `add_tween` will be ignored.
|
|
insert_tween_if_needed(trace_settings)
|
|
kwargs['settings'] = trace_settings
|
|
|
|
# `caller_package` works by walking a fixed amount of frames up the stack
|
|
# to find the calling package. So if we let the original `__init__`
|
|
# function call it, our wrapper will mess things up.
|
|
if not kwargs.get('package', None):
|
|
# Get the packge for the third frame up from this one.
|
|
# - ddtrace.contrib.pyramid.path
|
|
# - ddtrace.vendor.wrapt
|
|
# - (this is the frame we want)
|
|
# DEV: Default is `level=2` which will give us the package from `wrapt`
|
|
kwargs['package'] = caller_package(level=3)
|
|
|
|
wrapped(*args, **kwargs)
|
|
trace_pyramid(instance)
|
|
|
|
|
|
def insert_tween_if_needed(settings):
|
|
tweens = settings.get('pyramid.tweens')
|
|
# If the list is empty, pyramid does not consider the tweens have been
|
|
# set explicitly.
|
|
# And if our tween is already there, nothing to do
|
|
if not tweens or not tweens.strip() or DD_TWEEN_NAME in tweens:
|
|
return
|
|
# pyramid.tweens.EXCVIEW is the name of built-in exception view provided by
|
|
# pyramid. We need our tween to be before it, otherwise unhandled
|
|
# exceptions will be caught before they reach our tween.
|
|
idx = tweens.find(pyramid.tweens.EXCVIEW)
|
|
if idx == -1:
|
|
settings['pyramid.tweens'] = tweens + '\n' + DD_TWEEN_NAME
|
|
else:
|
|
settings['pyramid.tweens'] = tweens[:idx] + DD_TWEEN_NAME + '\n' + tweens[idx:]
|