Files
2020-04-08 10:39:44 -07:00

164 lines
5.1 KiB
Python

"""
Settings for Datadog tracer are all namespaced in the DATADOG_TRACE setting.
For example your project's `settings.py` file might look like this::
DATADOG_TRACE = {
'TRACER': 'myapp.tracer',
}
This module provides the `setting` object, that is used to access
Datadog settings, checking for user settings first, then falling
back to the defaults.
"""
from __future__ import unicode_literals
import os
import importlib
from django.conf import settings as django_settings
from ...internal.logger import get_logger
log = get_logger(__name__)
# List of available settings with their defaults
DEFAULTS = {
'AGENT_HOSTNAME': 'localhost',
'AGENT_PORT': 8126,
'AUTO_INSTRUMENT': True,
'INSTRUMENT_CACHE': True,
'INSTRUMENT_DATABASE': True,
'INSTRUMENT_TEMPLATE': True,
'DEFAULT_DATABASE_PREFIX': '',
'DEFAULT_SERVICE': 'django',
'DEFAULT_CACHE_SERVICE': '',
'ENABLED': True,
'DISTRIBUTED_TRACING': True,
'ANALYTICS_ENABLED': None,
'ANALYTICS_SAMPLE_RATE': True,
'TRACE_QUERY_STRING': None,
'TAGS': {},
'TRACER': 'ddtrace.tracer',
}
# List of settings that may be in string import notation.
IMPORT_STRINGS = (
'TRACER',
)
# List of settings that have been removed
REMOVED_SETTINGS = ()
def import_from_string(val, setting_name):
"""
Attempt to import a class from a string representation.
"""
try:
# Nod to tastypie's use of importlib.
parts = val.split('.')
module_path, class_name = '.'.join(parts[:-1]), parts[-1]
module = importlib.import_module(module_path)
return getattr(module, class_name)
except (ImportError, AttributeError) as e:
msg = 'Could not import "{}" for setting "{}". {}: {}.'.format(
val,
setting_name,
e.__class__.__name__,
e,
)
raise ImportError(msg)
class DatadogSettings(object):
"""
A settings object, that allows Datadog settings to be accessed as properties.
For example:
from ddtrace.contrib.django.conf import settings
tracer = settings.TRACER
Any setting with string import paths will be automatically resolved
and return the class, rather than the string literal.
"""
def __init__(self, user_settings=None, defaults=None, import_strings=None):
if user_settings:
self._user_settings = self.__check_user_settings(user_settings)
self.defaults = defaults or DEFAULTS
if os.environ.get('DATADOG_ENV'):
self.defaults['TAGS'].update({'env': os.environ.get('DATADOG_ENV')})
if os.environ.get('DATADOG_SERVICE_NAME'):
self.defaults['DEFAULT_SERVICE'] = os.environ.get('DATADOG_SERVICE_NAME')
host = os.environ.get('DD_AGENT_HOST', os.environ.get('DATADOG_TRACE_AGENT_HOSTNAME'))
if host:
self.defaults['AGENT_HOSTNAME'] = host
port = os.environ.get('DD_TRACE_AGENT_PORT', os.environ.get('DATADOG_TRACE_AGENT_PORT'))
if port:
# if the agent port is a string, the underlying library that creates the socket
# stops working
try:
port = int(port)
except ValueError:
log.warning('DD_TRACE_AGENT_PORT is not an integer value; default to 8126')
else:
self.defaults['AGENT_PORT'] = port
self.import_strings = import_strings or IMPORT_STRINGS
@property
def user_settings(self):
if not hasattr(self, '_user_settings'):
self._user_settings = getattr(django_settings, 'DATADOG_TRACE', {})
# TODO[manu]: prevents docs import errors; provide a better implementation
if 'ENABLED' not in self._user_settings:
self._user_settings['ENABLED'] = not django_settings.DEBUG
return self._user_settings
def __getattr__(self, attr):
if attr not in self.defaults:
raise AttributeError('Invalid setting: "{}"'.format(attr))
try:
# Check if present in user settings
val = self.user_settings[attr]
except KeyError:
# Otherwise, fall back to defaults
val = self.defaults[attr]
# Coerce import strings into classes
if attr in self.import_strings:
val = import_from_string(val, attr)
# Cache the result
setattr(self, attr, val)
return val
def __check_user_settings(self, user_settings):
SETTINGS_DOC = 'http://pypi.datadoghq.com/trace/docs/#module-ddtrace.contrib.django'
for setting in REMOVED_SETTINGS:
if setting in user_settings:
raise RuntimeError(
'The "{}" setting has been removed, check "{}".'.format(setting, SETTINGS_DOC)
)
return user_settings
settings = DatadogSettings(None, DEFAULTS, IMPORT_STRINGS)
def reload_settings(*args, **kwargs):
"""
Triggers a reload when Django emits the reloading signal
"""
global settings
setting, value = kwargs['setting'], kwargs['value']
if setting == 'DATADOG_TRACE':
settings = DatadogSettings(value, DEFAULTS, IMPORT_STRINGS)