Commit 1fd579c5 authored by Fabrice Allain's avatar Fabrice Allain
Browse files

feat: new logging system for aria core

parent a785ce99
......@@ -424,7 +424,26 @@ def tickrot(axes, figure, rotype='horizontal', xaxis=True, yaxis=True):
figure.canvas.draw()
# TODO: Add another level when we use verbose options instead of displaying debug messages
class AbcLogFilter(logging.Filter):
abc_words = ("abc_funcName", "abc_lineno")
def filter(self, record):
"""Set default values for abc attributes according to the
original attribute in LogRecord object"""
reg = re.compile(r"(?P<prefix>[A-Za-z0-9]*(?=_))?_?(?P<name>\w+)")
for abc_word in self.abc_words:
if not hasattr(record, abc_word):
prefix, name = [reg.match(abc_word).groupdict()[_]
for _ in ('prefix', 'name')]
setattr(record, abc_word, getattr(record, name))
return True
# TODO: Add another level when we use verbose options instead of displaying
# debug messages
class CustomLogging(object):
"""
Customized python logging config
......@@ -433,7 +452,7 @@ class CustomLogging(object):
# "conf/logging.json")
default_file = "conf/logging.json"
def __init__(self, level=logging.INFO, desc=None):
def __init__(self, level=logging.INFO, desc=None, welcome=True):
"""
Parameters
......@@ -445,12 +464,11 @@ class CustomLogging(object):
"""
# TODO: detect path log filenames and makedirs if not exists
logging.basicConfig(level=level)
if desc:
self.msg = desc.strip()
else:
self.msg = ""
self.config = self.default_config()
self.welcome()
self.msg = desc.strip() if desc else ""
self.config = self.load_config()
self.update_log()
if welcome:
self.welcome()
def update_msg(self, desc):
"""
......@@ -470,12 +488,32 @@ class CustomLogging(object):
elif isinstance(self.msg, str):
self.msg = " - ".join((self.msg, desc.capitalize()))
def default_config(self):
""":return:"""
def update_log(self):
"""
Update logging config with config attribute
"""
logging.config.dictConfig(self.config)
def load_config(self, abc=False):
"""
Build default configuration from default json file
Returns
-------
config: dict
default configuration for logging
"""
# with open(self.default_file, 'rt') as f:
conf = pkgr.resource_stream(__name__, self.default_file).read().decode()
config = json.loads(conf)
logging.config.dictConfig(config)
# if abc:
# reg = re.compile(r"(?P<prefix>[A-Za-z0-9]*(?=_))?_?(?P<name>\w+)")
# for ft_name, formatter in config.get("formatters", {}).iteritems():
# prefix, name = [reg.match(ft_name).groupdict()[_]
# for _ in ('prefix', 'name')]
# if prefix == "abc" and name in config["formatters"]:
# config["formatters"][name] = config["formatters"][ft_name]
return config
def set_outdir(self, outdir):
......@@ -493,12 +531,10 @@ class CustomLogging(object):
"""
outdir = os.path.join(outdir,
"log") if "log" not in outdir else outdir
if not os.path.exists(os.path.abspath(outdir)):
os.makedirs(outdir)
else:
# Trick to avoid overwriting files with w mode after copy2 call
if os.path.exists(os.path.abspath(outdir)):
# Avoid overwriting files with w mode after copy2 call
shutil.rmtree(os.path.abspath(outdir))
os.makedirs(outdir)
os.makedirs(outdir)
if outdir and "handlers" in self.config:
for hand in self.config["handlers"]:
if "filename" in self.config["handlers"][hand]:
......@@ -508,7 +544,7 @@ class CustomLogging(object):
self.config["handlers"][hand]["filename"])))
self.config["handlers"][hand]["filename"] = newpath
shutil.copy2(oldpath, newpath)
logging.config.dictConfig(self.config)
self.update_log()
def welcome(self):
"""
......@@ -517,7 +553,7 @@ class CustomLogging(object):
-------
"""
desc = '''
desc = '''\
================================================================================
{:^80}
......
......@@ -6,7 +6,7 @@
"format": "%(levelname)-8s %(message)s"
},
"detail": {
"format": "[%(asctime)s] --- %(levelname)-8s --- %(message)s (%(filename)s:%(lineno)s)",
"format": "[%(asctime)s] --- %(levelname)s --- %(message)s (%(name)s.%(abc_funcName)s:%(abc_lineno)s)",
"datefmt": "%m/%d/%Y %I:%M:%S %p"
},
"colored": {
......@@ -14,7 +14,11 @@
"format": "%(log_color)s%(levelname)-8s%(reset)s %(message)s"
}
},
"filters": {
"abc_filter": {
"()": "aria.conbox.common.AbcLogFilter"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
......@@ -22,38 +26,40 @@
"formatter": "colored",
"stream": "ext://sys.stdout"
},
"info_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "INFO",
"formatter": "simple",
"filename": "/tmp/ariaec.log",
"filename": "/tmp/aria.log",
"mode": "a",
"encoding": "utf8"
},
"debug_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "DEBUG",
"formatter": "detail",
"filename": "/tmp/ariaec.debug",
"filename": "/tmp/aria.debug",
"mode": "a",
"encoding": "utf8"
"encoding": "utf8",
"filters": ["abc_filter"]
},
"error_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "ERROR",
"formatter": "detail",
"filename": "/tmp/ariaec.error",
"filename": "/tmp/aria.error",
"mode": "a",
"encoding": "utf8"
"encoding": "utf8",
"filters": ["abc_filter"]
}
},
"root": {
"level": "INFO",
"handlers": ["console", "info_file_handler", "error_file_handler",
"debug_file_handler"]
"handlers": [
"console",
"info_file_handler",
"error_file_handler",
"debug_file_handler"
]
}
}
\ No newline at end of file
......@@ -25,7 +25,6 @@
.. $Date: 2010/03/23 15:27:24 $ ..
.. .......................................................................... ..
"""
from .TypeChecking import *
from threading import Thread
from .ariabase import *
......@@ -245,11 +244,10 @@ class Job(Thread, AriaBaseClass):
# Remove the file path (if exists)
try:
os.unlink(filename)
os.unlink(checkfile)
except OSError:
pass
[os.unlink(foo) for foo in (filename, checkfile)]
except Exception as e:
LOG.exception(e)
# start job
d = self.getSettings().as_dict()
......@@ -328,8 +326,8 @@ class Job(Thread, AriaBaseClass):
# Remove if exists updated checkpoint script
try:
os.unlink(checkscript)
except OSError:
pass
except Exception as e:
LOG.exception(e)
if not self.isStopped() and terminated and checkpoint:
self.message('Job %s completed.' % job_desc)
......@@ -388,8 +386,8 @@ class JobScheduler(JobManager):
try:
f.close()
except:
pass
except Exception as e:
LOG.exception(e)
return reason
......
......@@ -29,13 +29,12 @@
from __future__ import absolute_import, division, print_function
from future.builtins import input
from threading import Lock
from .TypeChecking import *
import inspect
import pkg_resources as pkgr
from .TypeChecking import *
from ..conbox.common import CustomLogging
# set correct python-path
ARIA_ENV = 'ARIA2'
MODULE_NAME = 'aria'
# TODO: sounds like PATH_MODULES global variable is not used anymore
......@@ -60,6 +59,10 @@ VL_LOW = 1
# Print lock
PRINT_LOCK = Lock()
# Logging Config
LOG_CONF = CustomLogging(welcome=False)
LOG = logging.getLogger(__name__)
def get_path():
"""Ask user to give aria installation path in ARIA2 env variable"""
......@@ -158,9 +161,9 @@ class AriaBaseClass:
display_messages = 1
display_deprecated = 1
display_debug = 0
warnings_as_errors = 0
wrap_lines = 1
line_length = 80
description_length = 100
......@@ -170,6 +173,7 @@ class AriaBaseClass:
# BB extendNmr
log_gui = None
log_stdout = 1
logger = LOG
# BB
check_type.active = 0
verbose_level = 0
......@@ -188,7 +192,8 @@ class AriaBaseClass:
if new_flag:
data_path = pkgr.resource_filename(MODULE_NAME, 'data')
toppar_path = pkgr.resource_filename(MODULE_NAME, 'cns/toppar')
protocols_path = pkgr.resource_filename(MODULE_NAME, 'cns/protocols')
protocols_path = pkgr.resource_filename(MODULE_NAME,
'cns/protocols')
analysis_path = pkgr.resource_filename(MODULE_NAME,
'cns/protocols/analysis')
......@@ -213,7 +218,8 @@ class AriaBaseClass:
be assigned with its own name. it will be used when displaying
warnings, errors, messages etc.
"""
self.logger = logging.getLogger(self.__module__)
if settings is not None:
self.setSettings(settings)
else:
......@@ -321,14 +327,14 @@ class AriaBaseClass:
check_string(tag)
check_string(msg)
from . import tools as tools
if self.wrap_lines:
lines = tools.make_block(msg, self.line_length - len(tag))
else:
lines = [msg]
lines = tools.indent(lines, tag)
return lines
......@@ -338,18 +344,27 @@ class AriaBaseClass:
name = self._name
else:
name = self.__class__.__name__
return '%s [%s]: ' % (prefix, name)
def __print(self, prefix, msg, verbose_level):
return ' '.join(filter(None, (prefix, "[" + name + "]"))) + ': '
def __print(self, prefix, msg, verbose_level, func=None):
if verbose_level <= self.verbose_level or self.display_debug:
tag = prefix
prefix = self.__compile_name("")
lines = self.__format(prefix, msg)
if self.log_gui:
self.log_gui.write(lines + '\n')
if self.log_stdout:
with PRINT_LOCK:
print(lines)
kw = {"extra": {
"abc_name": func.co_filename,
"abc_funcName": func.co_name,
"abc_lineno": func.co_firstlineno}}
self.logger.warning(lines, **kw) if "WARNING" in tag else \
self.logger.error(lines, **kw) if "ERROR" in tag else \
self.logger.info(lines, **kw)
# print(lines)
self.__log(lines)
def __log(self, s):
......@@ -375,10 +390,11 @@ class AriaBaseClass:
"""
func = inspect.currentframe().f_back.f_code
if self.display_messages:
prefix = self.__compile_name(prefix)
msg = str(msg)
self.__print(prefix, msg, verbose_level)
self.__print(prefix, msg, verbose_level, func=func)
def warning(self, msg, verbose_level=VL_STANDARD):
"""
......@@ -396,11 +412,11 @@ class AriaBaseClass:
"""
if self.display_warnings:
msg = str(msg)
if self.warnings_as_errors:
self.error(msg=msg)
else:
......
......@@ -2830,8 +2830,8 @@ Could not create working directory for CNS analysis scripts ("%s").""" % (
else:
try:
os.unlink(fn)
except:
pass
except Exception as e:
LOG.exception(e)
if action_performed:
msg = {1: '(un)ambig.tbl files in %s have been gzipped',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment