Example #1
0
def sanitize_http_headers(client, event):
    """
    Sanitizes http request/response headers
    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """
    # request headers
    try:
        headers = event["context"]["request"]["headers"]
        event["context"]["request"]["headers"] = varmap(
            _sanitize,
            headers,
            sanitize_field_names=client.config.sanitize_field_names)
    except (KeyError, TypeError):
        pass

    # response headers
    try:
        headers = event["context"]["response"]["headers"]
        event["context"]["response"]["headers"] = varmap(
            _sanitize,
            headers,
            sanitize_field_names=client.config.sanitize_field_names)
    except (KeyError, TypeError):
        pass

    return event
Example #2
0
def sanitize_http_request_cookies(client, event):
    """
    Sanitizes http request cookies
    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """

    # sanitize request.cookies dict
    try:
        cookies = event["context"]["request"]["cookies"]
        event["context"]["request"]["cookies"] = varmap(
            _sanitize,
            cookies,
            sanitize_field_names=client.config.sanitize_field_names)
    except (KeyError, TypeError):
        pass

    # sanitize request.header.cookie string
    try:
        cookie_string = force_text(
            event["context"]["request"]["headers"]["cookie"], errors="replace")
        event["context"]["request"]["headers"]["cookie"] = _sanitize_string(
            cookie_string,
            "; ",
            "=",
            sanitize_field_names=client.config.sanitize_field_names)
    except (KeyError, TypeError):
        pass
    return event
Example #3
0
    def capture(client, exc_info=None, **kwargs):
        culprit = exc_value = exc_type = exc_module = frames = exc_traceback = None
        new_exc_info = False
        if not exc_info or exc_info is True:
            new_exc_info = True
            exc_info = sys.exc_info()

        if not exc_info:
            raise ValueError("No exception found")

        try:
            exc_type, exc_value, exc_traceback = exc_info

            frames = get_stack_info(
                iter_traceback_frames(exc_traceback),
                with_locals=client.config.collect_local_variables in ("errors", "all"),
                library_frame_context_lines=client.config.source_lines_error_library_frames,
                in_app_frame_context_lines=client.config.source_lines_error_app_frames,
                include_paths_re=client.include_paths_re,
                exclude_paths_re=client.exclude_paths_re,
                locals_processor_func=lambda local_var: varmap(
                    lambda k, val: shorten(
                        val,
                        list_length=client.config.local_var_list_max_length,
                        string_length=client.config.local_var_max_length,
                    ),
                    local_var,
                ),
            )

            culprit = get_culprit(frames, client.config.include_paths, client.config.exclude_paths)

            if hasattr(exc_type, "__module__"):
                exc_module = exc_type.__module__
                exc_type = exc_type.__name__
            else:
                exc_module = None
                exc_type = exc_type.__name__
        finally:
            if new_exc_info:
                try:
                    del exc_info
                    del exc_traceback
                except Exception as e:
                    logger.exception(e)
        if "message" in kwargs:
            message = kwargs["message"]
        else:
            message = "%s: %s" % (exc_type, to_unicode(exc_value)) if exc_value else str(exc_type)

        return {
            "id": "%032x" % random.getrandbits(128),
            "culprit": culprit,
            "exception": {
                "message": message,
                "type": keyword_field(str(exc_type)),
                "module": keyword_field(str(exc_module)),
                "stacktrace": frames,
            },
        }
Example #4
0
    def capture(client, exc_info=None, **kwargs):
        culprit = exc_value = exc_type = exc_module = frames = exc_traceback = None
        new_exc_info = False
        if not exc_info or exc_info is True:
            new_exc_info = True
            exc_info = sys.exc_info()

        if not exc_info:
            raise ValueError('No exception found')

        try:
            exc_type, exc_value, exc_traceback = exc_info

            frames = varmap(
                lambda k, v: shorten(v),
                get_stack_info(
                    iter_traceback_frames(exc_traceback),
                    with_locals=client.config.collect_local_variables in ('errors', 'all'),
                    with_source_context=client.config.collect_source in ('errors', 'all'),
                    include_paths_re=client.include_paths_re,
                    exclude_paths_re=client.exclude_paths_re,
                )
            )

            culprit = get_culprit(frames, client.config.include_paths, client.config.exclude_paths)

            if hasattr(exc_type, '__module__'):
                exc_module = exc_type.__module__
                exc_type = exc_type.__name__
            else:
                exc_module = None
                exc_type = exc_type.__name__
        finally:
            if new_exc_info:
                try:
                    del exc_info
                    del exc_traceback
                except Exception as e:
                    logger.exception(e)
        if 'message' in kwargs:
            message = kwargs['message']
        else:
            message = '%s: %s' % (exc_type, to_unicode(exc_value)) if exc_value else str(exc_type)

        return {
            'id': str(uuid.uuid4()),
            'culprit': culprit,
            'exception': {
                'message': message,
                'type': str(exc_type),
                'module': str(exc_module),
                'stacktrace': frames,
            }
        }
Example #5
0
 def frames_collector_func():
     return self._get_stack_info_for_trace(
         stacks.iter_stack_frames(skip_top_modules=skip_modules),
         library_frame_context_lines=self.config.source_lines_span_library_frames,
         in_app_frame_context_lines=self.config.source_lines_span_app_frames,
         with_locals=self.config.collect_local_variables in ('all', 'transactions'),
         locals_processor_func=lambda local_var: varmap(lambda k, v: shorten(
             v,
             list_length=self.config.local_var_list_max_length,
             string_length=self.config.local_var_max_length,
         ), local_var)
     )
Example #6
0
    def capture(client, exc_info=None, **kwargs):
        culprit = exc_value = exc_type = exc_module = frames = None
        new_exc_info = False
        if not exc_info or exc_info is True:
            new_exc_info = True
            exc_info = sys.exc_info()

        if not exc_info:
            raise ValueError('No exception found')

        try:
            exc_type, exc_value, exc_traceback = exc_info

            frames = varmap(
                lambda k, v: shorten(v,
                                     string_length=client.string_max_length,
                                     list_length=client.list_max_length),
                get_stack_info((iter_traceback_frames(exc_traceback))))

            culprit = get_culprit(frames, client.include_paths,
                                  client.exclude_paths)

            if hasattr(exc_type, '__module__'):
                exc_module = exc_type.__module__
                exc_type = exc_type.__name__
            else:
                exc_module = None
                exc_type = exc_type.__name__
        finally:
            if new_exc_info:
                try:
                    del exc_info
                    del exc_traceback
                except Exception as e:
                    logger.exception(e)

        return {
            'id': str(uuid.uuid4()),
            'culprit': culprit,
            'exception': {
                'message':
                '%s: %s' % (exc_type, to_unicode(exc_value))
                if exc_value else str(exc_type),
                'type':
                str(exc_type),
                'module':
                str(exc_module),
                'stacktrace':
                frames,
            }
        }
Example #7
0
    def __init__(self, config=None, **defaults):
        # configure loggers first
        cls = self.__class__
        self.logger = logging.getLogger('%s.%s' % (cls.__module__, cls.__name__))
        self.error_logger = logging.getLogger('elasticapm.errors')
        self.state = ClientState()

        self.instrumentation_store = None
        self.processors = []
        self.filter_exception_types_dict = {}
        self._send_timer = None
        self._transports = {}
        self._service_info = None

        self.config = Config(config, default_dict=defaults)
        if self.config.errors:
            for msg in self.config.errors.values():
                self.error_logger.error(msg)
            self.config.disable_send = True
            return

        self._transport_class = import_string(self.config.transport_class)

        for exc_to_filter in (self.config.filter_exception_types or []):
            exc_to_filter_type = exc_to_filter.split(".")[-1]
            exc_to_filter_module = ".".join(exc_to_filter.split(".")[:-1])
            self.filter_exception_types_dict[exc_to_filter_type] = exc_to_filter_module

        self.processors = [import_string(p) for p in self.config.processors] if self.config.processors else []

        self.instrumentation_store = TransactionsStore(
            lambda: self._get_stack_info_for_trace(
                stacks.iter_stack_frames(),
                library_frame_context_lines=self.config.source_lines_span_library_frames,
                in_app_frame_context_lines=self.config.source_lines_span_app_frames,
                with_locals=self.config.collect_local_variables in ('all', 'transactions'),
                locals_processor_func=lambda local_var: varmap(lambda k, v: shorten(
                    v,
                    list_length=self.config.local_var_list_max_length,
                    string_length=self.config.local_var_max_length,
                ), local_var)
            ),
            collect_frequency=self.config.flush_interval,
            sample_rate=self.config.transaction_sample_rate,
            max_spans=self.config.transaction_max_spans,
            max_queue_size=self.config.max_queue_size,
            ignore_patterns=self.config.transactions_ignore_patterns,
        )
        self.include_paths_re = stacks.get_path_regex(self.config.include_paths) if self.config.include_paths else None
        self.exclude_paths_re = stacks.get_path_regex(self.config.exclude_paths) if self.config.exclude_paths else None
        compat.atexit_register(self.close)
Example #8
0
def sanitize_http_request_headers(client, event):
    """
    Sanitizes http request headers

    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """
    try:
        headers = event['context']['request']['headers']
        event['context']['request']['headers'] = varmap(_sanitize, headers)
    except (KeyError, TypeError):
        pass
    return event
Example #9
0
def sanitize_http_wsgi_env(client, event):
    """
    Sanitizes WSGI environment variables

    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """
    try:
        env = event['context']['request']['env']
        event['context']['request']['env'] = varmap(_sanitize, env)
    except (KeyError, TypeError):
        pass
    return event
Example #10
0
def sanitize_http_wsgi_env(client, event):
    """
    Sanitizes WSGI environment variables
    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """
    try:
        env = event["context"]["request"]["env"]
        event["context"]["request"]["env"] = varmap(
            _sanitize, env, sanitize_field_names=client.config.sanitize_field_names
        )
    except (KeyError, TypeError):
        pass
    return event
Example #11
0
def sanitize_http_request_cookies(client, event):
    """
    Sanitizes http request cookies

    :param client: an ElasticAPM client
    :param event: a transaction or error event
    :return: The modified event
    """

    # sanitize request.cookies dict
    try:
        cookies = event['context']['request']['cookies']
        event['context']['request']['cookies'] = varmap(_sanitize, cookies)
    except (KeyError, TypeError):
        pass

    # sanitize request.header.cookie string
    try:
        cookie_string = event['context']['request']['headers']['cookie']
        event['context']['request']['headers']['cookie'] = _sanitize_string(
            cookie_string, '; ', '=')
    except (KeyError, TypeError):
        pass
    return event
Example #12
0
    def __init__(self, config=None, **inline):
        # configure loggers first
        cls = self.__class__
        self.logger = logging.getLogger("%s.%s" %
                                        (cls.__module__, cls.__name__))
        self.error_logger = logging.getLogger("elasticapm.errors")

        self.tracer = None
        self.processors = []
        self.filter_exception_types_dict = {}
        self._service_info = None

        self.config = Config(config, inline_dict=inline)
        if self.config.errors:
            for msg in self.config.errors.values():
                self.error_logger.error(msg)
            self.config.disable_send = True

        headers = {
            "Content-Type": "application/x-ndjson",
            "Content-Encoding": "gzip",
            "User-Agent": "elasticapm-python/%s" % elasticapm.VERSION,
        }

        if self.config.secret_token:
            headers["Authorization"] = "Bearer %s" % self.config.secret_token
        transport_kwargs = {
            "metadata": self._build_metadata(),
            "headers": headers,
            "verify_server_cert": self.config.verify_server_cert,
            "timeout": self.config.server_timeout,
            "max_flush_time": self.config.api_request_time / 1000.0,
            "max_buffer_size": self.config.api_request_size,
        }
        self._transport = import_string(self.config.transport_class)(
            compat.urlparse.urljoin(self.config.server_url,
                                    constants.EVENTS_API_PATH),
            **transport_kwargs)

        for exc_to_filter in self.config.filter_exception_types or []:
            exc_to_filter_type = exc_to_filter.split(".")[-1]
            exc_to_filter_module = ".".join(exc_to_filter.split(".")[:-1])
            self.filter_exception_types_dict[
                exc_to_filter_type] = exc_to_filter_module

        self.processors = [import_string(p) for p in self.config.processors
                           ] if self.config.processors else []

        if platform.python_implementation() == "PyPy":
            # PyPy introduces a `_functools.partial.__call__` frame due to our use
            # of `partial` in AbstractInstrumentedModule
            skip_modules = ("elasticapm.", "_functools")
        else:
            skip_modules = ("elasticapm.", )

        self.tracer = Tracer(
            frames_collector_func=lambda: list(
                stacks.iter_stack_frames(start_frame=inspect.currentframe(),
                                         skip_top_modules=skip_modules)),
            frames_processing_func=lambda frames: self.
            _get_stack_info_for_trace(
                frames,
                library_frame_context_lines=self.config.
                source_lines_span_library_frames,
                in_app_frame_context_lines=self.config.
                source_lines_span_app_frames,
                with_locals=self.config.collect_local_variables in
                ("all", "transactions"),
                locals_processor_func=lambda local_var: varmap(
                    lambda k, v: shorten(
                        v,
                        list_length=self.config.local_var_list_max_length,
                        string_length=self.config.local_var_max_length,
                    ),
                    local_var,
                ),
            ),
            queue_func=self.queue,
            sample_rate=self.config.transaction_sample_rate,
            max_spans=self.config.transaction_max_spans,
            span_frames_min_duration=self.config.span_frames_min_duration,
            ignore_patterns=self.config.transactions_ignore_patterns,
        )
        self.include_paths_re = stacks.get_path_regex(
            self.config.include_paths) if self.config.include_paths else None
        self.exclude_paths_re = stacks.get_path_regex(
            self.config.exclude_paths) if self.config.exclude_paths else None
        compat.atexit_register(self.close)
Example #13
0
    def _build_msg_for_logging(self,
                               event_type,
                               date=None,
                               context=None,
                               custom=None,
                               stack=None,
                               handled=True,
                               **kwargs):
        """
        Captures, processes and serializes an event into a dict object
        """
        transaction = get_transaction()
        if transaction:
            transaction_context = deepcopy(transaction.context)
        else:
            transaction_context = {}
        event_data = {}
        if custom is None:
            custom = {}
        if date is not None:
            warnings.warn(
                "The date argument is no longer evaluated and will be removed in a future release",
                DeprecationWarning)
        date = time.time()
        if stack is None:
            stack = self.config.auto_log_stacks
        if context:
            transaction_context.update(context)
            context = transaction_context
        else:
            context = transaction_context
        event_data["context"] = context
        if transaction and transaction.tags:
            context["tags"] = deepcopy(transaction.tags)

        # if '.' not in event_type:
        # Assume it's a builtin
        event_type = "elasticapm.events.%s" % event_type

        handler = self.get_handler(event_type)
        result = handler.capture(self, **kwargs)
        if self._filter_exception_type(result):
            return
        # data (explicit) culprit takes over auto event detection
        culprit = result.pop("culprit", None)
        if custom.get("culprit"):
            culprit = custom.pop("culprit")

        for k, v in compat.iteritems(result):
            if k not in event_data:
                event_data[k] = v

        log = event_data.get("log", {})
        if stack and "stacktrace" not in log:
            if stack is True:
                frames = stacks.iter_stack_frames(skip=3)
            else:
                frames = stack
            frames = stacks.get_stack_info(
                frames,
                with_locals=self.config.collect_local_variables
                in ("errors", "all"),
                library_frame_context_lines=self.config.
                source_lines_error_library_frames,
                in_app_frame_context_lines=self.config.
                source_lines_error_app_frames,
                include_paths_re=self.include_paths_re,
                exclude_paths_re=self.exclude_paths_re,
                locals_processor_func=lambda local_var: varmap(
                    lambda k, v: shorten(
                        v,
                        list_length=self.config.local_var_list_max_length,
                        string_length=self.config.local_var_max_length,
                    ),
                    local_var,
                ),
            )
            log["stacktrace"] = frames

        if "stacktrace" in log and not culprit:
            culprit = stacks.get_culprit(log["stacktrace"],
                                         self.config.include_paths,
                                         self.config.exclude_paths)

        if "level" in log and isinstance(log["level"], compat.integer_types):
            log["level"] = logging.getLevelName(log["level"]).lower()

        if log:
            event_data["log"] = log

        if culprit:
            event_data["culprit"] = culprit

        if "custom" in context:
            context["custom"].update(custom)
        else:
            context["custom"] = custom

        # Make sure all data is coerced
        event_data = transform(event_data)
        if "exception" in event_data:
            event_data["exception"]["handled"] = bool(handled)

        event_data["timestamp"] = int(date * 1000000)

        transaction = get_transaction()
        if transaction:
            if transaction.trace_parent:
                event_data["trace_id"] = transaction.trace_parent.trace_id
            event_data["parent_id"] = transaction.id
            event_data["transaction_id"] = transaction.id

        return event_data
Example #14
0
    def __init__(self, config=None, **inline):
        # configure loggers first
        cls = self.__class__
        self.logger = get_logger("%s.%s" % (cls.__module__, cls.__name__))
        self.error_logger = get_logger("elasticapm.errors")

        self.tracer = None
        self.processors = []
        self.filter_exception_types_dict = {}
        self._service_info = None

        config = Config(config, inline_dict=inline)
        if config.errors:
            for msg in config.errors.values():
                self.error_logger.error(msg)
            config.disable_send = True
        self.config = VersionedConfig(config, version=None)

        # Insert the log_record_factory into the logging library
        # The LogRecordFactory functionality is only available on python 3.2+
        if compat.PY3 and not self.config.disable_log_record_factory:
            record_factory = logging.getLogRecordFactory()
            # Only way to know if it's wrapped is to create a log record
            throwaway_record = record_factory(__name__, logging.DEBUG, __file__, 252, "dummy_msg", [], None)
            if not hasattr(throwaway_record, "elasticapm_labels"):
                self.logger.debug("Inserting elasticapm log_record_factory into logging")

                # Late import due to circular imports
                import elasticapm.handlers.logging as elastic_logging

                new_factory = elastic_logging.log_record_factory(record_factory)
                logging.setLogRecordFactory(new_factory)

        headers = {
            "Content-Type": "application/x-ndjson",
            "Content-Encoding": "gzip",
            "User-Agent": "elasticapm-python/%s" % elasticapm.VERSION,
        }

        if self.config.secret_token:
            headers["Authorization"] = "Bearer %s" % self.config.secret_token
        transport_kwargs = {
            "metadata": self._build_metadata(),
            "headers": headers,
            "verify_server_cert": self.config.verify_server_cert,
            "server_cert": self.config.server_cert,
            "timeout": self.config.server_timeout,
            "max_flush_time": self.config.api_request_time / 1000.0,
            "max_buffer_size": self.config.api_request_size,
            "processors": self.load_processors(),
        }
        self._api_endpoint_url = compat.urlparse.urljoin(
            self.config.server_url if self.config.server_url.endswith("/") else self.config.server_url + "/",
            constants.EVENTS_API_PATH,
        )
        self._transport = import_string(self.config.transport_class)(self._api_endpoint_url, **transport_kwargs)

        for exc_to_filter in self.config.filter_exception_types or []:
            exc_to_filter_type = exc_to_filter.split(".")[-1]
            exc_to_filter_module = ".".join(exc_to_filter.split(".")[:-1])
            self.filter_exception_types_dict[exc_to_filter_type] = exc_to_filter_module

        if platform.python_implementation() == "PyPy":
            # PyPy introduces a `_functools.partial.__call__` frame due to our use
            # of `partial` in AbstractInstrumentedModule
            skip_modules = ("elasticapm.", "_functools")
        else:
            skip_modules = ("elasticapm.",)

        self.tracer = Tracer(
            frames_collector_func=lambda: list(
                stacks.iter_stack_frames(
                    start_frame=inspect.currentframe(), skip_top_modules=skip_modules, config=self.config
                )
            ),
            frames_processing_func=lambda frames: self._get_stack_info_for_trace(
                frames,
                library_frame_context_lines=self.config.source_lines_span_library_frames,
                in_app_frame_context_lines=self.config.source_lines_span_app_frames,
                with_locals=self.config.collect_local_variables in ("all", "transactions"),
                locals_processor_func=lambda local_var: varmap(
                    lambda k, v: shorten(
                        v,
                        list_length=self.config.local_var_list_max_length,
                        string_length=self.config.local_var_max_length,
                        dict_length=self.config.local_var_dict_max_length,
                    ),
                    local_var,
                ),
            ),
            queue_func=self.queue,
            config=self.config,
            agent=self,
        )
        self.include_paths_re = stacks.get_path_regex(self.config.include_paths) if self.config.include_paths else None
        self.exclude_paths_re = stacks.get_path_regex(self.config.exclude_paths) if self.config.exclude_paths else None
        self._metrics = MetricsRegistry(
            self.config.metrics_interval / 1000.0, self.queue, ignore_patterns=self.config.disable_metrics
        )
        for path in self.config.metrics_sets:
            self._metrics.register(path)
        if self.config.breakdown_metrics:
            self._metrics.register("elasticapm.metrics.sets.breakdown.BreakdownMetricSet")
        compat.atexit_register(self.close)
        if self.config.central_config:
            self._config_updater = IntervalTimer(
                update_config, 1, "eapm conf updater", daemon=True, args=(self,), evaluate_function_interval=True
            )
            self._config_updater.start()
        else:
            self._config_updater = None
Example #15
0
    def _build_msg_for_logging(self,
                               event_type,
                               date=None,
                               context=None,
                               custom=None,
                               stack=None,
                               handled=True,
                               **kwargs):
        """
        Captures, processes and serializes an event into a dict object
        """
        transaction = get_transaction()
        if transaction:
            transaction_context = deepcopy(transaction.context)
        else:
            transaction_context = {}
        event_data = {}
        if custom is None:
            custom = {}
        if not date:
            date = datetime.datetime.utcnow()
        if stack is None:
            stack = self.config.auto_log_stacks
        if context:
            transaction_context.update(context)
            context = transaction_context
        else:
            context = transaction_context
        event_data['context'] = context
        if transaction and transaction.tags:
            context['tags'] = deepcopy(transaction.tags)

        # if '.' not in event_type:
        # Assume it's a builtin
        event_type = 'elasticapm.events.%s' % event_type

        handler = self.get_handler(event_type)
        result = handler.capture(self, **kwargs)
        if self._filter_exception_type(result):
            return
        # data (explicit) culprit takes over auto event detection
        culprit = result.pop('culprit', None)
        if custom.get('culprit'):
            culprit = custom.pop('culprit')

        for k, v in compat.iteritems(result):
            if k not in event_data:
                event_data[k] = v

        log = event_data.get('log', {})
        if stack and 'stacktrace' not in log:
            if stack is True:
                frames = stacks.iter_stack_frames(skip=3)
            else:
                frames = stack
            frames = stacks.get_stack_info(
                frames,
                with_locals=self.config.collect_local_variables
                in ('errors', 'all'),
                library_frame_context_lines=self.config.
                source_lines_error_library_frames,
                in_app_frame_context_lines=self.config.
                source_lines_error_app_frames,
                include_paths_re=self.include_paths_re,
                exclude_paths_re=self.exclude_paths_re,
                locals_processor_func=lambda local_var: varmap(
                    lambda k, v: shorten(
                        v,
                        list_length=self.config.local_var_list_max_length,
                        string_length=self.config.local_var_max_length,
                    ), local_var))
            log['stacktrace'] = frames

        if 'stacktrace' in log and not culprit:
            culprit = stacks.get_culprit(log['stacktrace'],
                                         self.config.include_paths,
                                         self.config.exclude_paths)

        if 'level' in log and isinstance(log['level'], compat.integer_types):
            log['level'] = logging.getLevelName(log['level']).lower()

        if log:
            event_data['log'] = log

        if culprit:
            event_data['culprit'] = culprit

        if 'custom' in context:
            context['custom'].update(custom)
        else:
            context['custom'] = custom

        # Run the data through processors
        for processor in self.processors:
            event_data = processor(self, event_data)

        # Make sure all data is coerced
        event_data = transform(event_data)
        if 'exception' in event_data:
            event_data['exception']['handled'] = bool(handled)

        event_data.update({
            'timestamp':
            date.strftime(constants.TIMESTAMP_FORMAT),
        })

        transaction = get_transaction()
        if transaction:
            event_data['transaction'] = {'id': transaction.id}

        return self._build_msg({'errors': [event_data]})
Example #16
0
    def __init__(self, config=None, **inline):
        # configure loggers first
        cls = self.__class__
        self.logger = get_logger("%s.%s" % (cls.__module__, cls.__name__))
        self.error_logger = get_logger("elasticapm.errors")

        self._pid = None
        self._thread_starter_lock = threading.Lock()
        self._thread_managers = {}

        self.tracer = None
        self.processors = []
        self.filter_exception_types_dict = {}
        self._service_info = None

        self.check_python_version()

        config = Config(config, inline_dict=inline)
        if config.errors:
            for msg in config.errors.values():
                self.error_logger.error(msg)
            config.disable_send = True
        if config.service_name == "python_service":
            self.logger.warning(
                "No custom SERVICE_NAME was set -- using non-descript default 'python_service'"
            )
        self.config = VersionedConfig(config, version=None)

        # Insert the log_record_factory into the logging library
        # The LogRecordFactory functionality is only available on python 3.2+
        if compat.PY3 and not self.config.disable_log_record_factory:
            record_factory = logging.getLogRecordFactory()
            # Only way to know if it's wrapped is to create a log record
            throwaway_record = record_factory(__name__, logging.DEBUG,
                                              __file__, 252, "dummy_msg", [],
                                              None)
            if not hasattr(throwaway_record, "elasticapm_labels"):
                self.logger.debug(
                    "Inserting elasticapm log_record_factory into logging")

                # Late import due to circular imports
                import elasticapm.handlers.logging as elastic_logging

                new_factory = elastic_logging.log_record_factory(
                    record_factory)
                logging.setLogRecordFactory(new_factory)

        headers = {
            "Content-Type": "application/x-ndjson",
            "Content-Encoding": "gzip",
            "User-Agent": "elasticapm-python/%s" % elasticapm.VERSION,
        }

        transport_kwargs = {
            "headers": headers,
            "verify_server_cert": self.config.verify_server_cert,
            "server_cert": self.config.server_cert,
            "timeout": self.config.server_timeout,
            "processors": self.load_processors(),
        }
        self._api_endpoint_url = compat.urlparse.urljoin(
            self.config.server_url if self.config.server_url.endswith("/") else
            self.config.server_url + "/",
            constants.EVENTS_API_PATH,
        )
        transport_class = import_string(self.config.transport_class)
        self._transport = transport_class(self._api_endpoint_url, self,
                                          **transport_kwargs)
        self.config.transport = self._transport
        self._thread_managers["transport"] = self._transport

        for exc_to_filter in self.config.filter_exception_types or []:
            exc_to_filter_type = exc_to_filter.split(".")[-1]
            exc_to_filter_module = ".".join(exc_to_filter.split(".")[:-1])
            self.filter_exception_types_dict[
                exc_to_filter_type] = exc_to_filter_module

        if platform.python_implementation() == "PyPy":
            # PyPy introduces a `_functools.partial.__call__` frame due to our use
            # of `partial` in AbstractInstrumentedModule
            skip_modules = ("elasticapm.", "_functools")
        else:
            skip_modules = ("elasticapm.", )

        self.tracer = Tracer(
            frames_collector_func=lambda: list(
                stacks.iter_stack_frames(start_frame=inspect.currentframe(),
                                         skip_top_modules=skip_modules,
                                         config=self.config)),
            frames_processing_func=lambda frames: self.
            _get_stack_info_for_trace(
                frames,
                library_frame_context_lines=self.config.
                source_lines_span_library_frames,
                in_app_frame_context_lines=self.config.
                source_lines_span_app_frames,
                with_locals=self.config.collect_local_variables in
                ("all", "transactions"),
                locals_processor_func=lambda local_var: varmap(
                    lambda k, v: shorten(
                        v,
                        list_length=self.config.local_var_list_max_length,
                        string_length=self.config.local_var_max_length,
                        dict_length=self.config.local_var_dict_max_length,
                    ),
                    local_var,
                ),
            ),
            queue_func=self.queue,
            config=self.config,
            agent=self,
        )
        self.include_paths_re = stacks.get_path_regex(
            self.config.include_paths) if self.config.include_paths else None
        self.exclude_paths_re = stacks.get_path_regex(
            self.config.exclude_paths) if self.config.exclude_paths else None
        self._metrics = MetricsRegistry(self)
        for path in self.config.metrics_sets:
            self._metrics.register(path)
        if self.config.breakdown_metrics:
            self._metrics.register(
                "elasticapm.metrics.sets.breakdown.BreakdownMetricSet")
        if self.config.prometheus_metrics:
            self._metrics.register(
                "elasticapm.metrics.sets.prometheus.PrometheusMetrics")
        self._thread_managers["metrics"] = self._metrics
        compat.atexit_register(self.close)
        if self.config.central_config:
            self._thread_managers["config"] = self.config
        else:
            self._config_updater = None
        if self.config.use_elastic_excepthook:
            self.original_excepthook = sys.excepthook
            sys.excepthook = self._excepthook
        if config.enabled:
            self.start_threads()

        # Save this Client object as the global CLIENT_SINGLETON
        set_client(self)
Example #17
0
    def build_msg_for_logging(self,
                              event_type,
                              data=None,
                              date=None,
                              extra=None,
                              stack=None,
                              **kwargs):
        """
        Captures, processes and serializes an event into a dict object
        """

        if data is None:
            data = {}
        if extra is None:
            extra = {}
        if not date:
            date = datetime.datetime.utcnow()
        if stack is None:
            stack = self.auto_log_stacks
        if 'context' not in data:
            data['context'] = context = {}
        else:
            context = data['context']

        # if '.' not in event_type:
        # Assume it's a builtin
        event_type = 'elasticapm.events.%s' % event_type

        handler = self.get_handler(event_type)
        result = handler.capture(self, data=data, **kwargs)
        if self._filter_exception_type(result):
            return
        # data (explicit) culprit takes over auto event detection
        culprit = result.pop('culprit', None)
        if data.get('culprit'):
            culprit = data['culprit']

        for k, v in six.iteritems(result):
            if k not in data:
                data[k] = v

        log = data.get('log', {})
        if stack and 'stacktrace' not in log:
            if stack is True:
                frames = iter_stack_frames()
            else:
                frames = stack
            frames = varmap(
                lambda k, v: shorten(v,
                                     string_length=self.string_max_length,
                                     list_length=self.list_max_length),
                stacks.get_stack_info(frames))
            log['stacktrace'] = frames

        if 'stacktrace' in log and not culprit:
            culprit = get_culprit(log['stacktrace'], self.include_paths,
                                  self.exclude_paths)

        if 'level' in log and isinstance(log['level'], six.integer_types):
            log['level'] = logging.getLevelName(log['level']).lower()

        if log:
            data['log'] = log

        if culprit:
            data['culprit'] = culprit

        context['custom'] = extra

        # Run the data through processors
        for processor in self.processors:
            data = processor(self, data)

        # Make sure all data is coerced
        data = transform(data)

        data.update({
            'timestamp': date.strftime(defaults.TIMESTAMP_FORMAT),
        })

        return self.build_msg({'errors': [data]})
Example #18
0
 def func(frame):
     if 'vars' in frame:
         frame['vars'] = varmap(_sanitize, frame['vars'])
Example #19
0
    def capture(client, exc_info=None, **kwargs):
        culprit = exc_value = exc_type = exc_module = frames = exc_traceback = None
        new_exc_info = False
        if not exc_info or exc_info is True:
            new_exc_info = True
            exc_info = sys.exc_info()

        if exc_info == (None, None, None):
            raise ValueError("No exception found: capture_exception requires an active exception.")

        try:
            exc_type, exc_value, exc_traceback = exc_info

            frames = get_stack_info(
                iter_traceback_frames(exc_traceback, config=client.config),
                with_locals=client.config.collect_local_variables in ("errors", "all"),
                library_frame_context_lines=client.config.source_lines_error_library_frames,
                in_app_frame_context_lines=client.config.source_lines_error_app_frames,
                include_paths_re=client.include_paths_re,
                exclude_paths_re=client.exclude_paths_re,
                locals_processor_func=lambda local_var: varmap(
                    lambda k, val: shorten(
                        val,
                        list_length=client.config.local_var_list_max_length,
                        string_length=client.config.local_var_max_length,
                        dict_length=client.config.local_var_dict_max_length,
                    ),
                    local_var,
                ),
            )

            culprit = kwargs.get("culprit", None) or get_culprit(
                frames, client.config.include_paths, client.config.exclude_paths
            )

            if hasattr(exc_type, "__module__"):
                exc_module = exc_type.__module__
                exc_type = exc_type.__name__
            else:
                exc_module = None
                exc_type = exc_type.__name__
        finally:
            if new_exc_info:
                try:
                    del exc_info
                    del exc_traceback
                except Exception as e:
                    logger.exception(e)
        if "message" in kwargs:
            message = kwargs["message"]
        else:
            message = "%s: %s" % (exc_type, to_unicode(exc_value)) if exc_value else str(exc_type)

        data = {
            "id": "%032x" % random.getrandbits(128),
            "culprit": keyword_field(culprit),
            "exception": {
                "message": message,
                "type": keyword_field(str(exc_type)),
                "module": keyword_field(str(exc_module)),
                "stacktrace": frames,
            },
        }
        if compat.PY3:
            depth = kwargs.get("_exc_chain_depth", 0)
            if depth > EXCEPTION_CHAIN_MAX_DEPTH:
                return
            cause = exc_value.__cause__
            chained_context = exc_value.__context__

            # we follow the pattern of Python itself here and only capture the chained exception
            # if cause is not None and __suppress_context__ is False
            if chained_context and not (exc_value.__suppress_context__ and cause is None):
                if cause:
                    chained_exc_type = type(cause)
                    chained_exc_value = cause
                else:
                    chained_exc_type = type(chained_context)
                    chained_exc_value = chained_context
                chained_exc_info = chained_exc_type, chained_exc_value, chained_context.__traceback__

                chained_cause = Exception.capture(
                    client, exc_info=chained_exc_info, culprit="None", _exc_chain_depth=depth + 1
                )
                if chained_cause:
                    data["exception"]["cause"] = [chained_cause["exception"]]
        return data
Example #20
0
 def func(frame):
     if "vars" in frame:
         frame["vars"] = varmap(
             _sanitize,
             frame["vars"],
             sanitize_field_names=client.config.sanitize_field_names)
Example #21
0
 def func(frame):
     if "vars" in frame:
         frame["vars"] = varmap(_sanitize, frame["vars"])