Source code for BPG.logger

import logging
from datetime import datetime
import atexit
import sys

[docs]def setup_logger(log_path: str, log_filename: str = 'bpg.log', ) -> None: """ Configures the root logger so that all other loggers in BPG inherit from its properties. Parameters ---------- log_path : str The path to save the log files. log_filename : str The name of the primary output log file. Returns ------- """ # Set up the initial basic config for the root logger root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) root_logger.handlers = [] # Add a console handler out_handler = logging.StreamHandler() # If the verbose option is set to False, only display warnings and errors out_handler.setLevel(logging.INFO) # Add an output file to the root logger, overwrite the log file if it already exists file_handler = logging.FileHandler(log_path + '/' + log_filename, 'w') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('[%(filename)s:%(lineno)d] %(levelname)s - %(message)s') file_handler.setFormatter(formatter) # Add an output file to the root logger for INFO level logs and higher (debug can get messy) file_handler_info = logging.FileHandler(log_path + '/' + log_filename + '_INFO', 'w') file_handler_info.setLevel(logging.INFO) file_handler_info.setFormatter(formatter) root_logger.addHandler(file_handler) root_logger.addHandler(file_handler_info) root_logger.addHandler(out_handler) root_logger.addHandler(file_handler_info) # Add filter to prevent dataprep debug logs from hitting the main logger # Add filter to prevent duplicates of annoying messages duplicate_filter = DontRepeatFilter() out_handler.addFilter(duplicate_filter) # Print out the current date and time root_logger.info('##########################') root_logger.info('Starting BPG Build') time = datetime.now() root_logger.info(str(time)) root_logger.info('##########################') ################################################################################ # Dataprep logger ################################################################################ # Set up a dataprep logger for dumping dataprep debug data dataprep_logger = logging.getLogger('dataprep') dataprep_logger.setLevel(logging.DEBUG) dataprep_logger.propagate = False # Add a file stream for the dataprep logger dataprep_file_handler = logging.FileHandler(log_path + '/' 'dataprep_debug_dump.log', 'w') dataprep_file_handler.setLevel(logging.DEBUG) dataprep_file_handler.setFormatter(formatter) dataprep_logger.handlers = [] dataprep_logger.addHandler(dataprep_file_handler) # Print out the current date and time dataprep_logger.info('##########################') dataprep_logger.info('Starting BPG Build') dataprep_logger.info('Initializing dataprep_debug_dump.log') time = datetime.now() dataprep_logger.info(str(time)) dataprep_logger.info('##########################') ################################################################################ # Timing logger ################################################################################ # Set up a time information logger for dumping timing data when generating timing_logger = logging.getLogger('timing') timing_logger.setLevel(logging.DEBUG) timing_logger.propagate = False # Add a file stream for the dataprep logger timing_file_handler = logging.FileHandler(log_path + '/' 'timing.log', 'w') timing_file_handler.setLevel(logging.DEBUG) timing_formatter = logging.Formatter('%(message)-15s') timing_file_handler.setFormatter(timing_formatter) timing_logger.handlers = [] timing_logger.addHandler(timing_file_handler) # Print out the current date and time timing_logger.info('################################################################################') timing_logger.info(f'{"Time (s)":>15} | Operation') timing_logger.info('################################################################################') timing_logger.propagate = True """ Adding an end-of-execution summary message that indicates how many errors / warnings were generated during the run. """ try: def exit_register(fun, *args, **kwargs): """ Decorator that registers at post_execute. After its execution it unregisters itself for subsequent runs. """ def callback(): fun() ip.events.unregister('post_execute', callback) ip.events.register('post_execute', callback) ip = get_ipython() except NameError: from atexit import register as exit_register @exit_register def callback(): errors = 0 warnings = 0 with open(log_path + '/' + log_filename, 'r') as f: for line in f: if 'WARNING' in line: warnings += 1 if 'ERROR' in line: errors += 1 print(f'\n\n\n\n\n' f'{"BPG call completed":-^80}\n' f'Ran with {warnings} warnings.\n' f'{f"Ran with {errors} errors." if errors else ""}' f'\nSee {log_path}/{log_filename} for details.\n\n' ) duplicate_filter.clear_history()
[docs]class DontRepeatFilter: def __init__(self): self.dont_repeat_filters = { "vias are currently not considered in master bounding box calculations": 0, "round bounding boxes currently overestimate the size": 0 }
[docs] def filter(self, record): if record.msg not in self.dont_repeat_filters: return True else: if self.dont_repeat_filters[record.msg] == 0: self.dont_repeat_filters[record.msg] += 1 record.msg = '\n'.join([record.msg, 'ATTENTION: THE ABOVE WARNING WILL NOT BE REPEATED']) return True else: return False
[docs] def clear_history(self): for key in self.dont_repeat_filters: self.dont_repeat_filters[key] = 0
[docs] def add_key(self, key): self.dont_repeat_filters[key] = 0