Use LoggingContext for non-zero / unhandled top level system-wide
authorScott Gasch <[email protected]>
Sat, 10 Jun 2023 21:34:45 +0000 (14:34 -0700)
committerScott Gasch <[email protected]>
Sat, 10 Jun 2023 21:34:45 +0000 (14:34 -0700)
record.

src/pyutils/bootstrap.py
src/pyutils/logging_utils.py

index f22bc1755cb30febe5aa6e3b7a99a39ff6500f69..18cbc274a71083eb4526dccf18464147cb7e144c 100644 (file)
@@ -119,7 +119,7 @@ def handle_uncaught_exception(exc_type, exc_value, exc_tb):
     logger.exception(msg)
     print(msg, file=sys.stderr)
     try:
     logger.exception(msg)
     print(msg, file=sys.stderr)
     try:
-        logging_utils.unhandled_top_level_exception(exc_type)
+        logging_utils.unhandled_top_level_exception(exc_type, exc_value, exc_tb)
     except Exception:
         pass
     if issubclass(exc_type, KeyboardInterrupt):
     except Exception:
         pass
     if issubclass(exc_type, KeyboardInterrupt):
index 10b96eef09d1b71b92cfcf5a6743b6607da094ee..f5a0b7c7a87afb0de4c024ade5afe3d5bb20344a 100644 (file)
@@ -57,6 +57,7 @@ import logging
 import os
 import re
 import sys
 import os
 import re
 import sys
+from logging import FileHandler
 from logging.config import fileConfig
 from logging.handlers import RotatingFileHandler, SysLogHandler
 from typing import Any, Callable, Dict, Iterable, List, Optional, Union
 from logging.config import fileConfig
 from logging.handlers import RotatingFileHandler, SysLogHandler
 from typing import Any, Callable, Dict, Iterable, List, Optional, Union
@@ -1203,9 +1204,15 @@ class OutputMultiplexerContext(OutputMultiplexer, contextlib.ContextDecorator):
         return True
 
 
         return True
 
 
-def _timestamp() -> str:
-    ts = datetime.datetime.now(pytz.timezone('US/Pacific'))
-    return ts.strftime("%Y/%m/%dT%H:%M:%S.%f%z")
+def _get_systemwide_abnormal_exit_handler(filename: str) -> FileHandler:
+    handler = FileHandler(filename)
+    handler.setFormatter(
+        MillisecondAwareFormatter(
+            fmt=_construct_logging_format(),
+            datefmt=config.config["logging_date_format"],
+        )
+    )
+    return handler
 
 
 def non_zero_return_value(ret: Any):
 
 
 def non_zero_return_value(ret: Any):
@@ -1219,18 +1226,17 @@ def non_zero_return_value(ret: Any):
     try:
         record = config.config['logging_non_zero_exits_record_path']
         if record:
     try:
         record = config.config['logging_non_zero_exits_record_path']
         if record:
+            logger = logging.getLogger()
+            handler = _get_systemwide_abnormal_exit_handler(record)
             program = config.PROGRAM_NAME
             args = config.ORIG_ARGV
             program = config.PROGRAM_NAME
             args = config.ORIG_ARGV
-            with open(record, 'a') as af:
-                print(
-                    f'{_timestamp()}: {program} ({args}) exited with non-zero value {ret}.',
-                    file=af,
-                )
+            with LoggingContext(logger, handlers=[handler], level=logging.INFO):
+                logger.info('%s (%s) exited with non-zero value %s', program, args, ret)
     except Exception:
         pass
 
 
     except Exception:
         pass
 
 
-def unhandled_top_level_exception(exc_type: type):
+def unhandled_top_level_exception(exc_type: type, exc_value, exc_tb):
     """
     Special method hooked from bootstrap.py to optionally keep a system-wide
     record of unhandled top level exceptions.
     """
     Special method hooked from bootstrap.py to optionally keep a system-wide
     record of unhandled top level exceptions.
@@ -1241,12 +1247,21 @@ def unhandled_top_level_exception(exc_type: type):
     try:
         record = config.config['logging_unhandled_top_level_exceptions_record_path']
         if record:
     try:
         record = config.config['logging_unhandled_top_level_exceptions_record_path']
         if record:
+            logger = logging.getLogger()
+            handler = _get_systemwide_abnormal_exit_handler(record)
             program = config.PROGRAM_NAME
             args = config.ORIG_ARGV
             program = config.PROGRAM_NAME
             args = config.ORIG_ARGV
-            with open(record, 'a') as af:
-                print(
-                    f'{_timestamp()}: {program} ({args}) took unhandled top level exception {exc_type}',
-                    file=af,
+            site_file = exc_tb.tb_frame.f_code.co_filename
+            site_lineno = exc_tb.tb_lineno
+            with LoggingContext(logger, handlers=[handler], level=logging.INFO):
+                logger.info(
+                    '%s (%s) took an unhandled top-level exception (type=%s(%s)) at %s:%s',
+                    program,
+                    args,
+                    exc_type.__name__,
+                    exc_value,
+                    site_file,
+                    site_lineno,
                 )
     except Exception:
         pass
                 )
     except Exception:
         pass