Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • calibration/pycalibration
1 result
Show changes
Commits on Source (3)
%% Cell type:code id:98e38fec tags: %% Cell type:code id:98e38fec tags:
``` python ``` python
in_folder = "./" # input folder in_folder = "./" # input folder
out_folder = "./" # output folder out_folder = "./" # output folder
``` ```
%% Cell type:code id:7fbce574 tags: %% Cell type:code id:7fbce574 tags:
``` python ``` python
import logging import logging
``` ```
%% Cell type:markdown id:ba0663ca tags: %% Cell type:markdown id:ba0663ca tags:
## INFO/DEBUG ## INFO/DEBUG
%% Cell type:code id:a3b5e455 tags: %% Cell type:code id:a3b5e455 tags:
``` python ``` python
# This wont be logged
logging.info("Logging some (INFO)rmation") logging.info("Logging some (INFO)rmation")
``` ```
%% Cell type:markdown id:1bf72c57 tags: %% Cell type:markdown id:1bf72c57 tags:
## WARNINGS ## WARNINGS
%% Cell type:code id:c0d290a1 tags: %% Cell type:code id:c0d290a1 tags:
``` python ``` python
import warnings import warnings
from cal_tools.warnings import CalWarning from cal_tools.warnings import CalibrationWarning
class TestCalWarning(CalWarning): class TestCalWarning(CalibrationWarning):
"""Base class for custom user warnings""" """Base class for custom user warnings"""
pass pass
def warn_user(message, warning_class): def warn_user(message, warning_class):
warnings.warn(message, warning_class) warnings.warn(message, warning_class)
if 1 < 2: if 1 < 2:
warn_user('This inequality is true!', TestCalWarning) warn_user('This inequality is true!', TestCalWarning)
``` ```
%% Cell type:code id:9b79ea47 tags: %% Cell type:code id:9b79ea47 tags:
``` python ``` python
# This wont be logged
logging.warning("This is a warning message using logging standard library.") logging.warning("This is a warning message using logging standard library.")
``` ```
%% Cell type:markdown id:2b22e2e0 tags: %% Cell type:markdown id:2b22e2e0 tags:
## ERRORS ## ERRORS
%% Cell type:code id:0f3bfeb7 tags: %% Cell type:code id:0f3bfeb7 tags:
``` python ``` python
# This wont be logged
logging.error("Logging some (ERROR) without failing the notebook") logging.error("Logging some (ERROR) without failing the notebook")
``` ```
%% Cell type:code id:c3b87719 tags: %% Cell type:code id:c3b87719 tags:
``` python ``` python
from cal_tools.exceptions import CalError from cal_tools.exceptions import CalibrationError
raise CalError('Calibration Failure') raise CalibrationError('Calibration Failure')
``` ```
......
class CalibrationError(Exception):
pass
class CalWarning(UserWarning): class CalibrationWarning(UserWarning):
pass pass
\ No newline at end of file
...@@ -6,15 +6,30 @@ import warnings ...@@ -6,15 +6,30 @@ import warnings
import IPython import IPython
from pythonjsonlogger import jsonlogger from pythonjsonlogger import jsonlogger
from cal_tools.warnings import CalibrationWarning
NOTEBOOK_NAME = os.getenv('CAL_NOTEBOOK_NAME', 'Unknown notebook') NOTEBOOK_NAME = os.getenv('CAL_NOTEBOOK_NAME', 'Unknown notebook')
JOB_ID = os.getenv('SLURM_JOB_ID', 'local') JOB_ID = os.getenv('SLURM_JOB_ID', 'local')
class ContextFilter(logging.Filter): class ContextFilter(logging.Filter):
def filter(self, record): def filter(self, record):
record.notebook = NOTEBOOK_NAME # Only allow records that come from exception handlers
record.job_id = JOB_ID if getattr(record, 'from_exception_handler', False):
return True record.notebook = NOTEBOOK_NAME
record.job_id = JOB_ID
return True
return False
def get_class_hierarchy(cls):
"""Helper function to get the full class hierarchy"""
class_hierarchy = []
current_class = cls
while current_class and current_class != object:
class_hierarchy.append(current_class.__name__)
current_class = current_class.__base__
return '.'.join(reversed(class_hierarchy))
class CustomJsonFormatter(jsonlogger.JsonFormatter): class CustomJsonFormatter(jsonlogger.JsonFormatter):
...@@ -25,23 +40,15 @@ class CustomJsonFormatter(jsonlogger.JsonFormatter): ...@@ -25,23 +40,15 @@ class CustomJsonFormatter(jsonlogger.JsonFormatter):
log_record['level'] = record.levelname log_record['level'] = record.levelname
log_record['filename'] = record.filename log_record['filename'] = record.filename
log_record['lineno'] = record.lineno log_record['lineno'] = record.lineno
log_record['class'] = getattr(record, 'class', 'DefaultClass')
# Get log_class from extra parameters (set in our warning/error handlers)
exc_info = getattr(record, 'exc_info', None) if hasattr(record, 'log_class'):
if exc_info and exc_info[0]: log_record['log_class'] = record.log_class
exc_class = exc_info[0]
class_hierarchy = []
current_class = exc_class
while current_class and current_class != Exception:
class_hierarchy.append(current_class.__name__)
current_class = current_class.__base__
class_hierarchy.append('Exception')
log_record['class'] = '.'.join(reversed(class_hierarchy))
else:
log_record['class'] = getattr(record, 'class', 'DefaultClass')
if record.exc_info: if record.exc_info:
log_record['exc_info'] = self.formatException(record.exc_info) log_record['exc_info'] = self.formatException(record.exc_info)
exc_class = record.exc_info[0]
log_record['class'] = get_class_hierarchy(exc_class)
# Create a logger # Create a logger
...@@ -51,7 +58,7 @@ logger.setLevel(logging.INFO) ...@@ -51,7 +58,7 @@ logger.setLevel(logging.INFO)
# Define a custom JSON format # Define a custom JSON format
formatter = CustomJsonFormatter( formatter = CustomJsonFormatter(
'%(timestamp)s %(level)s %(filename)s %(lineno)d ' '%(timestamp)s %(level)s %(filename)s %(lineno)d '
'%(notebook)s %(job_id)s %(class)s %(message)s') '%(notebook)s %(job_id)s %(log_class)s %(message)s')
# Function to create a file handler with job-specific JSON log file # Function to create a file handler with job-specific JSON log file
...@@ -70,15 +77,14 @@ warning_handler = create_job_specific_handler(logging.WARNING, 'warnings') ...@@ -70,15 +77,14 @@ warning_handler = create_job_specific_handler(logging.WARNING, 'warnings')
# Keep console handler for notebook and slurm.out stdout # Keep console handler for notebook and slurm.out stdout
console_handler = logging.StreamHandler() console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) console_handler.setLevel(logging.INFO)
console_formatter = logging.Formatter('%(levelname)s: %(message)s')
console_handler.setFormatter(console_formatter)
# Avoid errors being logged in warnings.json
warning_handler.addFilter(lambda record: record.levelno < logging.ERROR)
# Add the custom filter to handlers # Add the custom filter to handlers
context_filter = ContextFilter() context_filter = ContextFilter()
error_handler.addFilter(context_filter) error_handler.addFilter(context_filter)
warning_handler.addFilter(context_filter) warning_handler.addFilter(context_filter)
warning_handler.addFilter(lambda record: record.levelno < logging.ERROR)
console_handler.addFilter(context_filter) console_handler.addFilter(context_filter)
# Add handlers to logger # Add handlers to logger
...@@ -91,6 +97,12 @@ handling_error = False ...@@ -91,6 +97,12 @@ handling_error = False
def safe_handle_error(exc_type, exc_value, exc_traceback): def safe_handle_error(exc_type, exc_value, exc_traceback):
global handling_error global handling_error
# Added this block to skip sys.exit()
if exc_type in (SystemExit, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
if handling_error: # Avoid infinite loop of errors. if handling_error: # Avoid infinite loop of errors.
sys.stderr.write("Recursive error detected!\n") sys.stderr.write("Recursive error detected!\n")
traceback.print_exception( traceback.print_exception(
...@@ -103,7 +115,8 @@ def safe_handle_error(exc_type, exc_value, exc_traceback): ...@@ -103,7 +115,8 @@ def safe_handle_error(exc_type, exc_value, exc_traceback):
extra={ extra={
'notebook': NOTEBOOK_NAME, 'notebook': NOTEBOOK_NAME,
'job_id': JOB_ID, 'job_id': JOB_ID,
'class': exc_type.__name__ if exc_type else 'DefaultErrorClass', # noqa 'log_class': get_class_hierarchy(exc_type),
'from_exception_handler': True
}, },
exc_info=(exc_type, exc_value, exc_traceback) exc_info=(exc_type, exc_value, exc_traceback)
) )
...@@ -118,12 +131,13 @@ def safe_handle_error(exc_type, exc_value, exc_traceback): ...@@ -118,12 +131,13 @@ def safe_handle_error(exc_type, exc_value, exc_traceback):
def handle_warning(message, category, filename, lineno, file=None, line=None): def handle_warning(message, category, filename, lineno, file=None, line=None):
try: try:
logger.warning( logger.warning(
"Warning occurred: %s, File: %s, Line: %d", "%s",
message, filename, lineno, message,
extra={ extra={
'notebook': NOTEBOOK_NAME, 'notebook': NOTEBOOK_NAME,
'job_id': JOB_ID, 'job_id': JOB_ID,
'class': category.__name__ if category else 'DefaultWarningClass', # noqa 'log_class': get_class_hierarchy(category),
'from_exception_handler': True
} }
) )
except Exception as log_error: except Exception as log_error:
...@@ -134,6 +148,11 @@ def handle_warning(message, category, filename, lineno, file=None, line=None): ...@@ -134,6 +148,11 @@ def handle_warning(message, category, filename, lineno, file=None, line=None):
sys.excepthook = safe_handle_error sys.excepthook = safe_handle_error
warnings.showwarning = handle_warning warnings.showwarning = handle_warning
# Set up warnings filter
warnings.filterwarnings("ignore") # Ignore all warnings
# Except CalibrationWarning and subclasses
warnings.simplefilter("default", CalibrationWarning)
# Override IPython's exception handling # Override IPython's exception handling
def custom_showtraceback(self, *args, **kwargs): def custom_showtraceback(self, *args, **kwargs):
......