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, }, }
def capture(client, param_message=None, message=None, level=None, logger_name=None, **kwargs): if message: param_message = {'message': message} params = param_message.get('params') message = param_message[ 'message'] % params if params else param_message['message'] data = kwargs.get('data', {}) message_data = { 'id': str(uuid.uuid4()), 'log': { 'level': keyword_field(level or 'error'), 'logger_name': keyword_field(logger_name or '__root__'), 'message': message, 'param_message': keyword_field(param_message['message']), } } if isinstance(data.get('stacktrace'), dict): message_data['log']['stacktrace'] = data['stacktrace']['frames'] if kwargs.get('exception'): message_data['culprit'] = kwargs['exception']['culprit'] message_data['exception'] = kwargs['exception']['exception'] return message_data
def get_user_info(self, request): user_info = {} if not hasattr(request, 'user'): return user_info try: user = request.user if hasattr(user, 'is_authenticated'): if callable(user.is_authenticated): user_info['is_authenticated'] = user.is_authenticated() else: user_info['is_authenticated'] = bool(user.is_authenticated) if hasattr(user, 'id'): user_info['id'] = encoding.keyword_field(user.id) if hasattr(user, 'get_username'): user_info['username'] = encoding.keyword_field( user.get_username()) elif hasattr(user, 'username'): user_info['username'] = encoding.keyword_field(user.username) if hasattr(user, 'email'): user_info['email'] = user.email except DatabaseError: # If the connection is closed or similar, we'll just skip this return {} return user_info
def capture(client, param_message=None, message=None, level=None, logger_name=None, **kwargs): if message: param_message = {"message": message} params = param_message.get("params") message = param_message[ "message"] % params if params else param_message["message"] data = kwargs.get("data", {}) message_data = { "id": "%032x" % random.getrandbits(128), "log": { "level": keyword_field(level or "error"), "logger_name": keyword_field(logger_name or "__root__"), "message": message, "param_message": keyword_field(param_message["message"]), }, } if isinstance(data.get("stacktrace"), dict): message_data["log"]["stacktrace"] = data["stacktrace"]["frames"] if kwargs.get("exception"): message_data["culprit"] = kwargs["exception"]["culprit"] message_data["exception"] = kwargs["exception"]["exception"] return message_data
def get_url_dict(event: dict) -> dict: """ Reconstruct URL from API Gateway """ headers = event.get("headers", {}) protocol = headers.get("X-Forwarded-Proto", headers.get("x-forwarded-proto", "https")) host = headers.get("Host", headers.get("host", "")) stage = "/" + (nested_key(event, "requestContext", "stage") or "") path = event.get("path", event.get("rawPath", "").split(stage)[-1]) port = headers.get("X-Forwarded-Port", headers.get("x-forwarded-port")) query = "" if "rawQueryString" in event: query = event["rawQueryString"] elif event.get("queryStringParameters"): query = "?" for k, v in compat.iteritems(event["queryStringParameters"]): query += "{}={}".format(k, v) url = protocol + "://" + host + stage + path + query url_dict = { "full": encoding.keyword_field(url), "protocol": protocol, "hostname": encoding.keyword_field(host), "pathname": encoding.keyword_field(stage + path), } if port: url_dict["port"] = port if query: url_dict["search"] = encoding.keyword_field(query) return url_dict
def sanitize_http_request_querystring(client, event): """ Sanitizes http request query string :param client: an ElasticAPM client :param event: a transaction or error event :return: The modified event """ try: query_string = force_text(event["context"]["request"]["url"]["search"], errors="replace") except (KeyError, TypeError): return event if "=" in query_string: sanitized_query_string = _sanitize_string( query_string, "&", "=", sanitize_field_names=client.config.sanitize_field_names) full_url = event["context"]["request"]["url"]["full"] # we need to pipe the sanitized string through encoding.keyword_field to ensure that the maximum # length of keyword fields is still ensured. event["context"]["request"]["url"]["search"] = keyword_field( sanitized_query_string) event["context"]["request"]["url"]["full"] = keyword_field( full_url.replace(query_string, sanitized_query_string)) return event
def get_service_info(self): if self._service_info: return self._service_info language_version = platform.python_version() if hasattr(sys, "pypy_version_info"): runtime_version = ".".join(map(str, sys.pypy_version_info[:3])) else: runtime_version = language_version result = { "name": keyword_field(self.config.service_name), "environment": keyword_field(self.config.environment), "version": keyword_field(self.config.service_version), "agent": {"name": "python", "version": elasticapm.VERSION}, "language": {"name": "python", "version": keyword_field(platform.python_version())}, "runtime": { "name": keyword_field(platform.python_implementation()), "version": keyword_field(runtime_version), }, } if self.config.framework_name: result["framework"] = { "name": keyword_field(self.config.framework_name), "version": keyword_field(self.config.framework_version), } if self.config.service_node_name: result["node"] = {"configured_name": keyword_field(self.config.service_node_name)} self._service_info = result return result
def to_dict(self): result = { "id": self.id, "transaction_id": self.transaction.id, "trace_id": self.transaction.trace_parent.trace_id, "parent_id": self.parent.id if self.parent else self.transaction.id, "name": encoding.keyword_field(self.name), "type": encoding.keyword_field(self.type), "timestamp": int(self.timestamp * 1000000), # microseconds "duration": self.duration * 1000, # milliseconds "context": self.context, } if self.frames: result["stacktrace"] = self.frames return result
def get_url_dict(url): parse_result = compat.urlparse.urlparse(url) url_dict = { "full": encoding.keyword_field(url), "protocol": parse_result.scheme + ":", "hostname": encoding.keyword_field(parse_result.hostname), "pathname": encoding.keyword_field(parse_result.path), } port = None if parse_result.port is None else str(parse_result.port) if port: url_dict["port"] = port if parse_result.query: url_dict["search"] = encoding.keyword_field("?" + parse_result.query) return url_dict
def get_url_dict(url): scheme, netloc, path, params, query, fragment = compat.urlparse.urlparse( url) if ':' in netloc: hostname, port = netloc.split(':') else: hostname, port = (netloc, None) url_dict = { 'full': encoding.keyword_field(url), 'protocol': scheme + ':', 'hostname': encoding.keyword_field(hostname), 'pathname': encoding.keyword_field(path), } if port: url_dict['port'] = port if query: url_dict['search'] = encoding.keyword_field('?' + query) return url_dict
def to_dict(self) -> dict: if ( self.composite and self.composite["compression_strategy"] == "same_kind" and nested_key(self.context, "destination", "service", "resource") ): name = "Calls to " + self.context["destination"]["service"]["resource"] else: name = self.name result = { "id": self.id, "transaction_id": self.transaction.id, "trace_id": self.transaction.trace_parent.trace_id, # use either the explicitly set parent_span_id, or the id of the parent, or finally the transaction id "parent_id": self.parent_span_id or (self.parent.id if self.parent else self.transaction.id), "name": encoding.keyword_field(name), "type": encoding.keyword_field(self.type), "subtype": encoding.keyword_field(self.subtype), "action": encoding.keyword_field(self.action), "timestamp": int(self.timestamp * 1000000), # microseconds "duration": self.duration * 1000, # milliseconds "outcome": self.outcome, } if self.transaction.sample_rate is not None: result["sample_rate"] = float(self.transaction.sample_rate) if self.sync is not None: result["sync"] = self.sync if self.labels: if self.context is None: self.context = {} self.context["tags"] = self.labels if self.context: self.autofill_resource_context() result["context"] = self.context if self.frames: result["stacktrace"] = self.frames if self.composite: result["composite"] = { "compression_strategy": self.composite["compression_strategy"], "sum": self.composite["sum"] * 1000, "count": self.composite["count"], } return result
def tag(self, **tags): """ Tag this span with one or multiple key/value tags. Both the values should be strings span_obj.tag(key1="value1", key2="value2") Note that keys will be dedotted, replacing dot (.), star (*) and double quote (") with an underscore (_) """ for key in tags.keys(): self.tags[TAG_RE.sub( "_", compat.text_type(key))] = encoding.keyword_field( compat.text_type(tags[key]))
def tag(**tags): """ Tags current transaction. Both key and value of the tag should be strings. """ transaction = get_transaction() for name, value in tags.items(): if not transaction: error_logger.warning( "Ignored tag %s. No transaction currently active.", name) return # replace invalid characters for Elasticsearch field names with underscores name = TAG_RE.sub("_", compat.text_type(name)) transaction.tags[compat.text_type(name)] = encoding.keyword_field( compat.text_type(value))