Coverage for structlog_google_cloud_logging/error.py: 69%
31 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-04-01 20:30 +0200
« prev ^ index » next coverage.py v7.2.2, created at 2023-04-01 20:30 +0200
1# https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.events/report
2# https://cloud.google.com/error-reporting/docs/formatting-error-messages#log-entry-examples
4import structlog.processors
6from structlog.typing import ExcInfo
7from io import StringIO
8import traceback
10ERROR_EVENT_TYPE = (
11 "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent"
12)
14CLOUD_LOGGING_KEY = "cloud-logging"
17class ErrorReport:
18 def __init__(self, log_level="CRITICAL"):
19 self.log_level = log_level
21 def setup(self):
22 return [
23 # structlog.processors.ExceptionRenderer(self.format_exception),
24 structlog.processors.format_exc_info,
25 self.__call__,
26 ]
28 def format_exception(self, exc_info: ExcInfo) -> str:
29 sio = StringIO()
31 header = f"{str(exc_info[0].__name__)}: {str(exc_info[1])}\n"
32 sio.write(header)
34 traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, sio)
35 s = sio.getvalue()
36 sio.close()
37 if s[-1:] == "\n":
38 s = s[:-1]
40 return s
42 def __call__(self, logger, method_name, event_dict):
43 exception = event_dict.pop("exception", None)
44 if exception is None:
45 return event_dict
47 message = event_dict[CLOUD_LOGGING_KEY].pop("message")
48 error_message = f"{message}\n{exception}"
50 # https://cloud.google.com/error-reporting/docs/formatting-error-messages
51 event_dict[CLOUD_LOGGING_KEY]["stack_trace"] = error_message
52 event_dict[CLOUD_LOGGING_KEY]["@type"] = ERROR_EVENT_TYPE
53 event_dict[CLOUD_LOGGING_KEY]["severity"] = self.log_level
55 return event_dict