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( encoding.force_text(user.get_username())) elif hasattr(user, "username"): user_info["username"] = encoding.keyword_field( encoding.force_text(user.username)) if hasattr(user, "email"): user_info["email"] = encoding.force_text(user.email) except DatabaseError: # If the connection is closed or similar, we'll just skip this return {} return user_info
def set_user_context(username=None, email=None, user_id=None): data = {} if username is not None: data["username"] = encoding.keyword_field(username) if email is not None: data["email"] = encoding.keyword_field(email) if user_id is not None: data["id"] = encoding.keyword_field(user_id) set_context(data, "user")
def test_transaction_keyword_truncation(zuqa_client): too_long = "x" * (KEYWORD_MAX_LENGTH + 1) expected = encoding.keyword_field(too_long) assert too_long != expected assert len(expected) == KEYWORD_MAX_LENGTH assert expected[-1] != "x" zuqa_client.begin_transaction(too_long) zuqa.tag(val=too_long) zuqa.set_user_context(username=too_long, email=too_long, user_id=too_long) with zuqa.capture_span(name=too_long, span_type=too_long): pass zuqa_client.end_transaction(too_long, too_long) zuqa_client.close() span = zuqa_client.events["span"][0] transaction = zuqa_client.events["transaction"][0] assert transaction["name"] == expected assert transaction["type"] == expected assert transaction["result"] == expected assert transaction["context"]["user"]["id"] == expected assert transaction["context"]["user"]["username"] == expected assert transaction["context"]["user"]["email"] == expected assert transaction["context"]["tags"]["val"] == expected assert span["type"] == expected assert span["name"] == expected
def get_system_info(self): system_data = { "hostname": keyword_field(self.config.hostname), "architecture": platform.machine(), "platform": platform.system().lower(), } system_data.update(cgroup.get_cgroup_container_metadata()) pod_name = os.environ.get( "KUBERNETES_POD_NAME") or system_data["hostname"] changed = False if "kubernetes" in system_data: k8s = system_data["kubernetes"] k8s["pod"]["name"] = pod_name else: k8s = {"pod": {"name": pod_name}} # get kubernetes metadata from environment if "KUBERNETES_NODE_NAME" in os.environ: k8s["node"] = {"name": os.environ["KUBERNETES_NODE_NAME"]} changed = True if "KUBERNETES_NAMESPACE" in os.environ: k8s["namespace"] = os.environ["KUBERNETES_NAMESPACE"] changed = True if "KUBERNETES_POD_UID" in os.environ: # this takes precedence over any value from /proc/self/cgroup k8s["pod"]["uid"] = os.environ["KUBERNETES_POD_UID"] changed = True if changed: system_data["kubernetes"] = k8s return system_data
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 to_dict(self): self.context["tags"] = self.labels result = { "id": self.id, "trace_id": self.trace_parent.trace_id, "name": encoding.keyword_field(self.name or ""), "type": encoding.keyword_field(self.transaction_type), "duration": self.duration * 1000, # milliseconds "result": encoding.keyword_field(str(self.result)), "timestamp": int(self.timestamp * 1000000), # microseconds "sampled": self.is_sampled, "span_count": {"started": self._span_counter - self.dropped_spans, "dropped": self.dropped_spans}, } if self.trace_parent: result["trace_id"] = self.trace_parent.trace_id # only set parent_id if this transaction isn't the root if self.trace_parent.span_id and self.trace_parent.span_id != self.id: result["parent_id"] = self.trace_parent.span_id if self.is_sampled: result["context"] = self.context return result
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 to_dict(self): 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(self.name), "type": encoding.keyword_field(self.type), "subtype": encoding.keyword_field(self.subtype), "action": encoding.keyword_field(self.action), "sync": self.sync, "timestamp": int(self.timestamp * 1000000), # microseconds "duration": self.duration * 1000, # milliseconds } if self.labels: if self.context is None: self.context = {} self.context["tags"] = self.labels if self.context: result["context"] = self.context if self.frames: result["stacktrace"] = self.frames return result
def tag(self, **tags): """ This method is deprecated, please use "label()" instead. 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 (_) :param tags: key/value pairs of tags :return: None """ for key in tags.keys(): self.labels[LABEL_RE.sub("_", compat.text_type(key))] = encoding.keyword_field(compat.text_type(tags[key]))
def test_message_keyword_truncation(sending_zuqa_client): too_long = "x" * (KEYWORD_MAX_LENGTH + 1) expected = encoding.keyword_field(too_long) sending_zuqa_client.capture_message(param_message={ "message": too_long, "params": [] }, logger_name=too_long, handled=False) sending_zuqa_client.close() error = sending_zuqa_client.httpserver.payloads[0][1]["error"] assert error["log"]["param_message"] == expected assert error["log"]["message"] == too_long # message is not truncated assert error["log"]["logger_name"] == expected
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": zuqa.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 test_error_keyword_truncation(sending_zuqa_client): too_long = "x" * (KEYWORD_MAX_LENGTH + 1) expected = encoding.keyword_field(too_long) # let's create a way too long Exception type with a way too long module name WayTooLongException = type(too_long.upper(), (Exception, ), {}) WayTooLongException.__module__ = too_long try: raise WayTooLongException() except WayTooLongException: with mock.patch("zuqa.events.get_culprit") as mock_get_culprit: mock_get_culprit.return_value = too_long sending_zuqa_client.capture_exception(handled=False) sending_zuqa_client.close() error = sending_zuqa_client.httpserver.payloads[0][1]["error"] assert error["exception"]["type"] == expected.upper() assert error["exception"]["module"] == expected assert error["culprit"] == expected
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 hasattr(exc_value, "_zuqa_span_id"): data["parent_id"] = exc_value._zuqa_span_id del exc_value._zuqa_span_id 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