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

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 

3 

4import structlog.processors 

5 

6from structlog.typing import ExcInfo 

7from io import StringIO 

8import traceback 

9 

10ERROR_EVENT_TYPE = ( 

11 "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent" 

12) 

13 

14CLOUD_LOGGING_KEY = "cloud-logging" 

15 

16 

17class ErrorReport: 

18 def __init__(self, log_level="CRITICAL"): 

19 self.log_level = log_level 

20 

21 def setup(self): 

22 return [ 

23 # structlog.processors.ExceptionRenderer(self.format_exception), 

24 structlog.processors.format_exc_info, 

25 self.__call__, 

26 ] 

27 

28 def format_exception(self, exc_info: ExcInfo) -> str: 

29 sio = StringIO() 

30 

31 header = f"{str(exc_info[0].__name__)}: {str(exc_info[1])}\n" 

32 sio.write(header) 

33 

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] 

39 

40 return s 

41 

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 

46 

47 message = event_dict[CLOUD_LOGGING_KEY].pop("message") 

48 error_message = f"{message}\n{exception}" 

49 

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 

54 

55 return event_dict