##// END OF EJS Templates
setup: change url to github
setup: change url to github

File last commit:

r153:32f4b641
r196:472d1df0 master
Show More
sentry.py
317 lines | 9.3 KiB | text/x-python | PythonLexer
# -*- coding: utf-8 -*-
# Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from datetime import timedelta
from appenlight.lib.enums import LogLevelPython, ParsedSentryEventType
EXCLUDED_LOG_VARS = [
"args",
"asctime",
"created",
"exc_info",
"exc_text",
"filename",
"funcName",
"levelname",
"levelno",
"lineno",
"message",
"module",
"msecs",
"msg",
"name",
"pathname",
"process",
"processName",
"relativeCreated",
"thread",
"threadName",
]
EXCLUDE_SENTRY_KEYS = [
"csp",
"culprit",
"event_id",
"exception",
"extra",
"level",
"logentry",
"logger",
"message",
"modules",
"platform",
"query",
"release",
"request",
"sentry.interfaces.Csp",
"sentry.interfaces.Exception",
"sentry.interfaces.Http",
"sentry.interfaces.Message",
"sentry.interfaces.Query",
"sentry.interfaces.Stacktrace",
"sentry.interfaces.Template",
"sentry.interfaces.User",
"sentry.interfaces.csp.Csp",
"sentry.interfaces.exception.Exception",
"sentry.interfaces.http.Http",
"sentry.interfaces.message.Message",
"sentry.interfaces.query.Query",
"sentry.interfaces.stacktrace.Stacktrace",
"sentry.interfaces.template.Template",
"sentry.interfaces.user.User",
"server_name",
"stacktrace",
"tags",
"template",
"time_spent",
"timestamp",
"user",
]
def get_keys(list_of_keys, json_body):
for k in list_of_keys:
if k in json_body:
return json_body[k]
def get_logentry(json_body):
key_names = [
"logentry",
"sentry.interfaces.message.Message",
"sentry.interfaces.Message",
]
logentry = get_keys(key_names, json_body)
return logentry
def get_exception(json_body):
parsed_exception = {}
key_names = [
"exception",
"sentry.interfaces.exception.Exception",
"sentry.interfaces.Exception",
]
exception = get_keys(key_names, json_body) or {}
if exception:
if isinstance(exception, dict):
exception = exception["values"][0]
else:
exception = exception[0]
parsed_exception["type"] = exception.get("type")
parsed_exception["value"] = exception.get("value")
parsed_exception["module"] = exception.get("module")
parsed_stacktrace = get_stacktrace(exception) or {}
parsed_exception = exception or {}
return parsed_exception, parsed_stacktrace
def get_stacktrace(json_body):
parsed_stacktrace = []
key_names = [
"stacktrace",
"sentry.interfaces.stacktrace.Stacktrace",
"sentry.interfaces.Stacktrace",
]
stacktrace = get_keys(key_names, json_body)
if stacktrace:
for frame in stacktrace["frames"]:
parsed_stacktrace.append(
{
"cline": frame.get("context_line", ""),
"file": frame.get("filename", ""),
"module": frame.get("module", ""),
"fn": frame.get("function", ""),
"line": frame.get("lineno", ""),
"vars": list(frame.get("vars", {}).items()),
}
)
return parsed_stacktrace
def get_template(json_body):
parsed_template = {}
key_names = [
"template",
"sentry.interfaces.template.Template",
"sentry.interfaces.Template",
]
template = get_keys(key_names, json_body)
if template:
for frame in template["frames"]:
parsed_template.append(
{
"cline": frame.get("context_line", ""),
"file": frame.get("filename", ""),
"fn": "",
"line": frame.get("lineno", ""),
"vars": [],
}
)
return parsed_template
def get_request(json_body):
parsed_http = {}
key_names = ["request", "sentry.interfaces.http.Http", "sentry.interfaces.Http"]
http = get_keys(key_names, json_body) or {}
for k, v in http.items():
if k == "headers":
parsed_http["headers"] = {}
for sk, sv in http["headers"].items():
parsed_http["headers"][sk.title()] = sv
else:
parsed_http[k.lower()] = v
return parsed_http
def get_user(json_body):
parsed_user = {}
key_names = ["user", "sentry.interfaces.user.User", "sentry.interfaces.User"]
user = get_keys(key_names, json_body)
if user:
parsed_user["id"] = user.get("id")
parsed_user["username"] = user.get("username")
parsed_user["email"] = user.get("email")
parsed_user["ip_address"] = user.get("ip_address")
return parsed_user
def get_query(json_body):
query = None
key_name = ["query", "sentry.interfaces.query.Query", "sentry.interfaces.Query"]
query = get_keys(key_name, json_body)
return query
def parse_sentry_event(json_body):
request_id = json_body.get("event_id")
# required
message = json_body.get("message")
log_timestamp = json_body.get("timestamp")
level = json_body.get("level")
if isinstance(level, int):
level = LogLevelPython.key_from_value(level)
namespace = json_body.get("logger")
language = json_body.get("platform")
# optional
server_name = json_body.get("server_name")
culprit = json_body.get("culprit")
release = json_body.get("release")
tags = json_body.get("tags", {})
if hasattr(tags, "items"):
tags = list(tags.items())
extra = json_body.get("extra", {})
if hasattr(extra, "items"):
extra = list(extra.items())
parsed_req = get_request(json_body)
user = get_user(json_body)
template = get_template(json_body)
query = get_query(json_body)
# other unidentified keys found
other_keys = [
(k, json_body[k]) for k in json_body.keys() if k not in EXCLUDE_SENTRY_KEYS
]
logentry = get_logentry(json_body)
if logentry:
message = logentry["message"]
exception, stacktrace = get_exception(json_body)
alt_stacktrace = get_stacktrace(json_body)
event_type = None
if not exception and not stacktrace and not alt_stacktrace and not template:
event_type = ParsedSentryEventType.LOG
event_dict = {
"log_level": level,
"message": message,
"namespace": namespace,
"request_id": request_id,
"server": server_name,
"date": log_timestamp,
"tags": tags,
}
event_dict["tags"].extend(
[(k, v) for k, v in extra if k not in EXCLUDED_LOG_VARS]
)
# other keys can be various object types
event_dict["tags"].extend([(k, v) for k, v in other_keys if isinstance(v, str)])
if culprit:
event_dict["tags"].append(("sentry_culprit", culprit))
if language:
event_dict["tags"].append(("sentry_language", language))
if release:
event_dict["tags"].append(("sentry_release", release))
if exception or stacktrace or alt_stacktrace or template:
event_type = ParsedSentryEventType.ERROR_REPORT
event_dict = {
"client": "sentry",
"error": message,
"namespace": namespace,
"request_id": request_id,
"server": server_name,
"start_time": log_timestamp,
"end_time": None,
"tags": tags,
"extra": extra,
"language": language,
"view_name": json_body.get("culprit"),
"http_status": None,
"username": None,
"url": parsed_req.get("url"),
"ip": None,
"user_agent": None,
"request": None,
"slow_calls": None,
"request_stats": None,
"traceback": None,
}
event_dict["extra"].extend(other_keys)
if release:
event_dict["tags"].append(("sentry_release", release))
event_dict["request"] = parsed_req
if "headers" in parsed_req:
event_dict["user_agent"] = parsed_req["headers"].get("User-Agent")
if "env" in parsed_req:
event_dict["ip"] = parsed_req["env"].get("REMOTE_ADDR")
ts_ms = int(json_body.get("time_spent") or 0)
if ts_ms > 0:
event_dict["end_time"] = event_dict["start_time"] + timedelta(
milliseconds=ts_ms
)
if stacktrace or alt_stacktrace or template:
event_dict["traceback"] = stacktrace or alt_stacktrace or template
for k in list(event_dict.keys()):
if event_dict[k] is None:
del event_dict[k]
if user:
event_dict["username"] = user["username"] or user["id"] or user["email"]
return event_dict, event_type