Beispiel #1
0
    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)
Beispiel #2
0
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
Beispiel #3
0
            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)
Beispiel #4
0
    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
Beispiel #6
0
    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",
            )
Beispiel #7
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
Beispiel #8
0
    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
Beispiel #9
0
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,