def transform(value, stack=None, context=None):
    # TODO: make this extendable
    if context is None:
        context = {}
    if stack is None:
        stack = []

    objid = id(value)
    if objid in context:
        return '<...>'

    context[objid] = 1
    transform_rec = lambda o: transform(o, stack + [value], context)

    if any(value is s for s in stack):
        ret = 'cycle'
    elif isinstance(value, (tuple, list, set, frozenset)):
        try:
            ret = type(value)(transform_rec(o) for o in value)
        except Exception:
            # We may be dealing with a namedtuple
            class value_type(list):
                __name__ = type(value).__name__

            ret = value_type(transform_rec(o) for o in value)
    elif isinstance(value, uuid.UUID):
        ret = repr(value)
    elif isinstance(value, dict):
        ret = dict(
            (to_unicode(k), transform_rec(v)) for k, v in six.iteritems(value))
    elif isinstance(value, six.text_type):
        ret = to_unicode(value)
    elif isinstance(value, six.binary_type):
        ret = to_string(value)
    elif not isinstance(value, six.class_types) and \
            _has_elasticapm_metadata(value):
        ret = transform_rec(value.__elasticapm__())
    elif isinstance(value, bool):
        ret = bool(value)
    elif isinstance(value, float):
        ret = float(value)
    elif isinstance(value, int):
        ret = int(value)
    elif six.PY2 and isinstance(value, long):  # noqa F821
        ret = long(value)  # noqa F821
    elif value is not None:
        try:
            ret = transform(repr(value))
        except:
            # It's common case that a model's __unicode__ definition may try to query the database
            # which if it was not cleaned up correctly, would hit a transaction aborted exception
            ret = u'<BadRepr: %s>' % type(value)
    else:
        ret = None
    del context[objid]
    return ret
Beispiel #2
0
def get_headers(environ):
    """
    Returns only proper HTTP headers.
    """
    for key, value in six.iteritems(environ):
        key = str(key)
        if key.startswith('HTTP_') and key not in \
           ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
            yield key[5:].replace('_', '-').lower(), value
        elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
            yield key.replace('_', '-').lower(), value
Beispiel #3
0
def varmap(func, var, context=None, name=None):
    """
    Executes ``func(key_name, value)`` on all values
    recurisively discovering dict and list scoped
    values.
    """
    if context is None:
        context = {}
    objid = id(var)
    if objid in context:
        return func(name, '<...>')
    context[objid] = 1
    if isinstance(var, dict):
        ret = dict((k, varmap(func, v, context, k)) for k, v in six.iteritems(var))
    elif isinstance(var, (list, tuple)):
        ret = [varmap(func, f, context, name) for f in var]
    else:
        ret = func(name, var)
    del context[objid]
    return ret
Beispiel #4
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]})
Beispiel #5
0
    def _emit(self, record, **kwargs):
        data = {}

        for k, v in six.iteritems(record.__dict__):
            if '.' not in k and k not in ('culprit', ):
                continue
            data[k] = v

        stack = getattr(record, 'stack', None)
        if stack is True:
            stack = iter_stack_frames()

        if stack:
            frames = []
            started = False
            last_mod = ''
            for item in stack:
                if isinstance(item, (list, tuple)):
                    frame, lineno = item
                else:
                    frame, lineno = item, item.f_lineno

                if not started:
                    f_globals = getattr(frame, 'f_globals', {})
                    module_name = f_globals.get('__name__', '')
                    if last_mod.startswith(
                            'logging'
                    ) and not module_name.startswith('logging'):
                        started = True
                    else:
                        last_mod = module_name
                        continue
                frames.append((frame, lineno))
            stack = frames

        extra = getattr(record, 'data', {})
        # Add in all of the data from the record that we aren't already capturing
        for k in record.__dict__.keys():
            if k in ('stack', 'name', 'args', 'msg', 'levelno', 'exc_text',
                     'exc_info', 'data', 'created', 'levelname', 'msecs',
                     'relativeCreated'):
                continue
            if k.startswith('_'):
                continue
            extra[k] = record.__dict__[k]

        date = datetime.datetime.utcfromtimestamp(record.created)

        # If there's no exception being processed,
        # exc_info may be a 3-tuple of None
        # http://docs.python.org/library/sys.html#sys.exc_info
        if record.exc_info and all(record.exc_info):
            handler = self.client.get_handler('elasticapm.events.Exception')

            data.update(handler.capture(self.client, exc_info=record.exc_info))
            # data['checksum'] = handler.get_hash(data)

        data['level'] = record.levelno
        data['logger'] = record.name
        return self.client.capture('Message',
                                   param_message={
                                       'message': record.msg,
                                       'params': record.args
                                   },
                                   stack=stack,
                                   data=data,
                                   extra=extra,
                                   date=date,
                                   **kwargs)