Skip to content

Commit

Permalink
Bugfix for logging that didn't appear in submodules (#247)
Browse files Browse the repository at this point in the history
* Improved logging setup.

* Transition to a LoggerUtil class.

* Addition of docstring to LoggerUtility + cleanup.
  • Loading branch information
Francesco Di Natale committed Apr 14, 2020
1 parent b7e4dab commit 7022c43
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 48 deletions.
63 changes: 15 additions & 48 deletions maestrowf/maestro.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

"""A script for launching a YAML study specification."""
from argparse import ArgumentParser, ArgumentError, RawTextHelpFormatter
import inspect
import logging
import os
import shutil
Expand All @@ -44,13 +43,13 @@
from maestrowf.datastructures.core import Study
from maestrowf.datastructures.environment import Variable
from maestrowf.utils import \
create_parentdir, create_dictionary, make_safe_path, \
create_parentdir, create_dictionary, LoggerUtility, make_safe_path, \
start_process


# Program Globals
ROOTLOGGER = logging.getLogger(inspect.getmodule(__name__))
LOGGER = logging.getLogger(__name__)
LOG_UTIL = LoggerUtility(LOGGER)

# Configuration globals
LFORMAT = "%(asctime)s - %(name)s:%(funcName)s:%(lineno)s - " \
Expand Down Expand Up @@ -168,8 +167,10 @@ def run_study(args):
output_path = make_safe_path(out_dir, *[out_name])
environment.add(Variable("OUTPUT_PATH", output_path))

# Now that we know outpath, set up logging.
setup_logging(args, output_path, spec.name.replace(" ", "_").lower())
# Set up file logging
create_parentdir(os.path.join(output_path, "logs"))
log_path = os.path.join(output_path, "logs", "{}.log".format(spec.name))
LOG_UTIL.add_file_handler(log_path, LFORMAT, args.debug_lvl)

# Check for pargs without the matching pgen
if args.pargs and not args.pgen:
Expand Down Expand Up @@ -389,49 +390,6 @@ def setup_argparser():
return parser


def setup_logging(args, path, name):
"""
Set up logging based on the ArgumentParser.
:param args: A Namespace object created by a parsed ArgumentParser.
:param path: A default path to be used if a log path is not specified by
user command line arguments.
:param name: The name of the log file.
"""
# If the user has specified a path, use that.
if args.logpath:
logpath = args.logpath
# Otherwise, we should just output to the OUTPUT_PATH.
else:
logpath = make_safe_path(path, *["logs"])

loglevel = args.debug_lvl * 10

# Create the FileHandler and add it to the logger.
create_parentdir(logpath)
formatter = logging.Formatter(LFORMAT)
ROOTLOGGER.setLevel(loglevel)

log_path = make_safe_path(logpath, *["{}.log".format(name)])
fh = logging.FileHandler(log_path)
fh.setLevel(loglevel)
fh.setFormatter(formatter)
ROOTLOGGER.addHandler(fh)

if args.logstdout:
# Add the StreamHandler
sh = logging.StreamHandler()
sh.setLevel(loglevel)
sh.setFormatter(formatter)
ROOTLOGGER.addHandler(sh)

# Print the level of logging.
LOGGER.info("INFO Logging Level -- Enabled")
LOGGER.warning("WARNING Logging Level -- Enabled")
LOGGER.critical("CRITICAL Logging Level -- Enabled")
LOGGER.debug("DEBUG Logging Level -- Enabled")


def main():
"""
Execute the main program's functionality.
Expand All @@ -444,6 +402,15 @@ def main():
parser = setup_argparser()
args = parser.parse_args()

# If we have requested to log stdout, set it up to be logged.
if args.logstdout:
LOG_UTIL.configure(LFORMAT, args.debug_lvl)

LOGGER.info("INFO Logging Level -- Enabled")
LOGGER.warning("WARNING Logging Level -- Enabled")
LOGGER.critical("CRITICAL Logging Level -- Enabled")
LOGGER.debug("DEBUG Logging Level -- Enabled")

rc = args.func(args)
sys.exit(rc)

Expand Down
68 changes: 68 additions & 0 deletions maestrowf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,71 @@ def create_dictionary(list_keyvalues, token=":"):
raise ValueError(msg)

return _dict


class LoggerUtility:
"""Utility class for setting up logging consistently."""

def __init__(self, logger):
"""
Initialize a new LoggerUtility class instance.
:param logger: An instance of a logger to configure.
"""
self._logger = logger

def configure(self, log_format, log_lvl=2):
"""
Configures the general logging facility.
:param log_format: String containing the desired logging format.
:param log_lvl: Integer level (1-5) to set the logger to.
"""
logging.basicConfig(level=self.map_level(log_lvl), format=log_format)

def add_stream_handler(self, log_format, log_lvl=2):
"""
Add a stream handler to logging.
:param log_format: String containing the desired logging format.
:param log_lvl: Integer level (1-5) to set the logger to.
"""
# Create the FileHandler and add it to the logger.
sh = logging.StreamHandler()
sh.setLevel(self.map_level(log_lvl))
sh.setFormatter(logging.Formatter(log_format))
self._logger.addHandler(sh)

def add_file_handler(self, log_path, log_format, log_lvl=2):
"""
Add a file handler to logging.
:param log_path: String containing the file path to store logging.
:param log_format: String containing the desired logging format.
:param log_lvl: Integer level (1-5) to set the logger to.
"""
# Create the FileHandler and add it to the logger.
formatter = logging.Formatter(log_format)

fh = logging.FileHandler(log_path)
fh.setLevel(self.map_level(log_lvl))
fh.setFormatter(formatter)
self._logger.addHandler(fh)

@staticmethod
def map_level(log_lvl):
"""
Map level 1-5 to their respective logging enumerations.
:param log_lvl: Integer level (1-5) representing logging verbosity.
"""
if log_lvl == 1:
return logging.DEBUG
elif log_lvl == 2:
return logging.INFO
elif log_lvl == 3:
return logging.WARNING
elif log_lvl == 4:
return logging.ERROR
else:
return logging.CRITICAL

0 comments on commit 7022c43

Please sign in to comment.