def __init__(self, conn, pin=None, cfg=None, cursor_cls=None): if not cfg: cfg = config.dbapi2 # Set default cursor class if one was not provided if not cursor_cls: # Do not trace `fetch*` methods by default cursor_cls = TracedCursor # Deprecation of config.dbapi2 requires we add a check if cfg.trace_fetch_methods or config.dbapi2.trace_fetch_methods: if config.dbapi2.trace_fetch_methods: debtcollector.deprecate( "ddtrace.config.dbapi2.trace_fetch_methods is now deprecated as the default integration config " "for TracedConnection. Use integration config specific to dbapi-compliant library.", removal_version="0.50.0", ) cursor_cls = FetchTracedCursor super(TracedConnection, self).__init__(conn) name = _get_vendor(conn) self._self_datadog_name = "{}.connection".format(name) db_pin = pin or Pin(service=name, app=name) db_pin.onto(self) # wrapt requires prefix of `_self` for attributes that are only in the # proxy (since some of our source objects will use `__slots__`) self._self_cursor_cls = cursor_cls self._self_config = _override_dbapi2_config(cfg)
def traced_populate(django, pin, func, instance, args, kwargs): """django.apps.registry.Apps.populate is the method used to populate all the apps. It is used as a hook to install instrumentation for 3rd party apps (like DRF). `populate()` works in 3 phases: - Phase 1: Initializes the app configs and imports the app modules. - Phase 2: Imports models modules for each app. - Phase 3: runs ready() of each app config. If all 3 phases successfully run then `instance.ready` will be `True`. """ # populate() can be called multiple times, we don't want to instrument more than once if instance.ready: log.debug("Django instrumentation already installed, skipping.") return func(*args, **kwargs) ret = func(*args, **kwargs) if not instance.ready: log.debug("populate() failed skipping instrumentation.") return ret settings = django.conf.settings if hasattr(settings, "DATADOG_TRACE"): debtcollector.deprecate( ("Using DATADOG_TRACE Django settings are no longer supported. ")) conf.configure_from_settings(pin, config.django, settings.DATADOG_TRACE) # Instrument databases if config.django.instrument_databases: try: instrument_dbs(django) except Exception: log.debug("Error instrumenting Django database connections", exc_info=True) # Instrument caches if config.django.instrument_caches: try: instrument_caches(django) except Exception: log.debug("Error instrumenting Django caches", exc_info=True) # Instrument Django Rest Framework if it's installed INSTALLED_APPS = getattr(settings, "INSTALLED_APPS", []) if "rest_framework" in INSTALLED_APPS: try: from .restframework import patch_restframework patch_restframework(django) except Exception: log.debug("Error patching rest_framework", exc_info=True) return ret
def traced_start_response(status_code, headers): code, _, _ = status_code.partition(" ") try: code = int(code) except ValueError: pass # Override root span resource name to be `<method> 404` for 404 requests # DEV: We do this because we want to make it easier to see all unknown requests together # Also, we do this to reduce the cardinality on unknown urls # DEV: If we have an endpoint or url rule tag, then we don't need to do this, # we still want `GET /product/<int:product_id>` grouped together, # even if it is a 404 if not s.get_tag(FLASK_ENDPOINT) and not s.get_tag( FLASK_URL_RULE): s.resource = u"{} {}".format(request.method, code) trace_utils.set_http_meta(s, config.flask, status_code=code, response_headers=headers) extra_error_codes = config.flask.get("extra_error_codes") if extra_error_codes: debtcollector.deprecate( ("ddtrace.config.flask['extra_error_codes'] is now deprecated, " "use ddtrace.config.http_server.error_statuses"), removal_version="0.47.0", ) if code in extra_error_codes: s.error = 1 return func(status_code, headers)
def __init__(self, conn, pin=None, cursor_cls=None): if not cursor_cls: # Do not trace `fetch*` methods by default cursor_cls = TracedSQLiteCursor if config.sqlite.trace_fetch_methods or config.dbapi2.trace_fetch_methods: if config.dbapi2.trace_fetch_methods: debtcollector.deprecate( "ddtrace.config.dbapi2.trace_fetch_methods is now deprecated as the default integration config " "for TracedConnection. Use integration config specific to dbapi-compliant library.", removal_version="0.50.0", ) cursor_cls = TracedSQLiteFetchCursor super(TracedSQLite, self).__init__(conn, pin=pin, cfg=config.sqlite, cursor_cls=cursor_cls)
def get_service_legacy(default=None): """Helper to print out a warning if old service name environment variables are used. If the environment variables are not in use, no deprecation warning is produced and `default` is returned. """ for old_env_key in ["DD_SERVICE_NAME", "DATADOG_SERVICE_NAME"]: if old_env_key in os.environ: debtcollector.deprecate( "'{}' is deprecated and will be removed in a future version. Please use DD_SERVICE instead." .format(old_env_key)) return os.getenv(old_env_key) return default
def _restore_from_shutdown(self): with self._shutdown_lock: if self.start_span is self._start_span: # Already restored return atexit.register(self._atexit) forksafe.register(self._child_after_fork) self.start_span = self._start_span self.trace = self._trace debtcollector.deprecate( "Tracing with a tracer that has been shut down is being deprecated. " "A new tracer should be created for generating new traces", version="1.0.0", )
def get_service_legacy(default=None): """Helper to get the old {DD,DATADOG}_SERVICE_NAME environment variables and output a deprecation warning if they are defined. Note that this helper should only be used for migrating integrations which use the {DD,DATADOG}_SERVICE_NAME variables to the new DD_SERVICE variable. If the environment variables are not in use, no deprecation warning is produced and `default` is returned. """ for old_env_key in ["DD_SERVICE_NAME", "DATADOG_SERVICE_NAME"]: if old_env_key in os.environ: debtcollector.deprecate(( "'{}' is deprecated and will be removed in a future version. Please use DD_SERVICE instead. " "Refer to our release notes on Github: https://github.com/DataDog/dd-trace-py/releases/tag/v0.36.0 " "for the improvements being made for service names." ).format(old_env_key)) return os.getenv(old_env_key) return default
def _get_analytics_settings(self): # type: () -> Tuple[Optional[bool], float] # We can have deprecated names for integrations used for analytics settings deprecated_name = deprecated_analytics_enabled = deprecated_analytics_sample_rate = None if hasattr(self, "_deprecated_name"): deprecated_name = self._deprecated_name deprecated_analytics_enabled = get_env( deprecated_name, "analytics_enabled") or os.environ.get( "DD_TRACE_%s_ANALYTICS_ENABLED" % deprecated_name.upper()) deprecated_analytics_sample_rate = get_env( deprecated_name, "analytics_sample_rate") or os.environ.get( "DD_TRACE_%s_ANALYTICS_SAMPLE_RATE" % deprecated_name.upper()) if deprecated_analytics_enabled is not None or deprecated_analytics_sample_rate is not None: debtcollector.deprecate( ("*DBAPI2_ANALYTICS* environment variables are now deprecated, " "use integration-specific configuration."), removal_version="0.50.0", ) # Set default analytics configuration, default is disabled # DEV: Default to `None` which means do not set this key # Inject environment variables for integration _ = (os.environ.get( "DD_TRACE_%s_ANALYTICS_ENABLED" % self.integration_name.upper()) or get_env(self.integration_name, "analytics_enabled") or deprecated_analytics_enabled) analytics_enabled = asbool(_) if _ is not None else None analytics_sample_rate = float( os.environ.get("DD_TRACE_%s_ANALYTICS_SAMPLE_RATE" % self.integration_name.upper()) or get_env(self.integration_name, "analytics_sample_rate") or deprecated_analytics_sample_rate or 1.0) return analytics_enabled, analytics_sample_rate
if config.logs_injection: # immediately patch logging if trace id injected from ddtrace import patch patch(logging=True) # DEV: Once basicConfig is called here, future calls to it cannot be used to # change the formatter since it applies the formatter to the root handler only # upon initializing it the first time. # See https://github.com/python/cpython/blob/112e4afd582515fcdcc0cde5012a4866e5cfda12/Lib/logging/__init__.py#L1550 # Debug mode from the tracer will do a basicConfig so only need to do this otherwise call_basic_config = asbool(os.environ.get("DD_CALL_BASIC_CONFIG", "false")) if not debug_mode and call_basic_config: deprecate( "ddtrace.tracer.logging.basicConfig", message= "`logging.basicConfig()` should be called in a user's application." " ``DD_CALL_BASIC_CONFIG`` will be removed in a future version.", ) if config.logs_injection: logging.basicConfig(format=DD_LOG_FORMAT) else: logging.basicConfig() log = get_logger(__name__) EXTRA_PATCHED_MODULES = { "bottle": True, "django": True, "falcon": True, "flask": True, "pylons": True,