Closed 4rimbach closed 3 years ago
This seems like a good option, using the python logging library is ideal for this, typically you might elevate logging with DEBUG mode.
To manage the syntax of this, and to provide context on what is logging, i embed this mixin into a class, and then call self.info('...') or self.error(e,'error message:'). This is helpful for identifying the source of problems since context is automatic.
The context is in brackets and message after that like: [beam: base_support]: load applied at 50% lenght fx: 0 fy: 10 fz: 0
.
From: https://github.com/SoundsSerious/ottermaticslib/blob/master/ottermatics/logging.py
'''Class to include easy formatting in subclasses'''
_log = None
log_on = True
#gelf = None
log_fmt = "[%(name)-24s]%(message)s"
log_silo = False
@property
def logger(self):
global LOG_LEVEL
if self._log is None:
self._log = logging.getLogger('otterlog_' +self.identity)
self._log.setLevel(level = LOG_LEVEL)
#Apply Filter Info
self._log.addFilter(self)
#Eliminate Outside Logging Interaction
if self.log_silo:
self._log.handlers = []
self._log.propagate = False
self.installSTDLogger()
#self.installGELFLogger()
return self._log
# def installGELFLogger(self):
# '''Installs GELF Logger'''
# gelf = graypy.GELFUDPHandler(host=GELF_HOST,port=12203, extra_fields=True)
# self._log.addHandler(gelf)
def resetLog(self):
self._log = None
def installSTDLogger(self):
'''We only want std logging to start'''
sh = logging.StreamHandler(sys.stdout)
peerlog = logging.Formatter(self.log_fmt)
sh.setFormatter(peerlog)
self._log.addHandler( sh )
def add_fields(self, record):
'''Overwrite this to modify logging fields'''
pass
def filter(self, record):
'''This acts as the interface for `logging.Filter`
Don't overwrite this, use `add_fields` instead.'''
record.name = self.identity.lower()
self.add_fields(record)
return True
def msg(self,*args):
'''Writes to log... this should be for raw data or something... least priorty'''
if self.log_on:
self.logger.log(0,self.extract_message(args))
def debug(self,*args):
'''Writes at a low level to the log file... usually this should
be detailed messages about what exactly is going on'''
if self.log_on:
self.logger.debug( self.extract_message(args))
def info(self,*args):
'''Writes to log but with info category, these are important typically
and inform about progress of process in general'''
if self.log_on:
self.logger.info( self.extract_message(args))
def warning(self,*args):
'''Writes to log as a warning'''
self.logger.warning(self.extract_message(args))
def error(self,error,msg=''):
'''Writes to log as a error'''
fmt = '{msg!r}|{err!r}'
tb = ''.join(traceback.format_exception(etype=type(error), value=error, tb=error.__traceback__))
self.logger.exception( fmt.format(msg=msg,err=tb))
def critical(self,*args):
'''A routine to communicate to the root of the server network that there is an issue'''
global SLACK_WEBHOOK_NOTIFICATION
msg = self.extract_message(args)
self.logger.critical(msg)
self.slack_notification(self.identity.title(),msg)
def slack_notification(self, category, message, stage=HOSTNAME):
global SLACK_WEBHOOK_NOTIFICATION
if SLACK_WEBHOOK_NOTIFICATION is None and 'SLACK_WEBHOOK_NOTIFICATION' in os.environ:
self.info('getting slack webhook')
SLACK_WEBHOOK_NOTIFICATION = os.environ['SLACK_WEBHOOK_NOTIFICATION']
headers = {'Content-type': 'application/json'}
data = {'text':"{category} on {stage}:\n```{message}```".format(\
category=category.upper(),\
stage=stage,\
message=message)}
self.info(f'Slack Notification : {SLACK_WEBHOOK_NOTIFICATION}:{category},{message}')
slack_note = requests.post(SLACK_WEBHOOK_NOTIFICATION,data= json.dumps(data).encode('ascii'),headers=headers)
def extract_message(self,args):
for arg in args:
if type(arg) is str:
return arg
return ''
@property
def identity(self):
return type(self).__name__
This feature is now available in version 0.0.39. By default the log is turned off. Use the log
argument in the Analyze
method to turn console logging on or off: FEModel3D.Analyze(log=True)
or FEModel3D.Analyze_PDelta(log=True)
.
In analysis functions (FEModel3D.Analyze() or .Analyze_PDelta()) add option to allow printing to be turned off
''' def Analyze(self, check_statics=False, max_iter=30, sparse=True, printing=True): ''' Performs first-order static analysis.
printing: bool, optional description ''' if printing == True: print('+-----------+') print('| Analyzing |') print('+-----------+') etc