Commits

Johannes Köster committed ce8a044

Refactoring logging.

  • Participants
  • Parent commits 1a16fa8

Comments (0)

Files changed (4)

File snakemake/__init__.py

 
 from snakemake.workflow import Workflow
 from snakemake.exceptions import print_exception
-from snakemake.logging import logger, init_logger
+import snakemake.logging as logging
 
 __author__ = "Johannes Köster"
 __version__ = "2.4.9"
     notemp=False,
     nodeps=False,
     jobscript=None,
-    timestamp=False):
+    timestamp=False,
+    log_handler=logging.console_handler):
     """
     Run snakemake on a given snakefile.
     Note: at the moment, this function is not thread-safe!
     lock              -- lock the working directory
     """
 
-    init_logger(nocolor=nocolor, stdout=dryrun, debug=debug, timestamp=timestamp)
+    if quiet:
+        log_handler = logging.quiet_console_handler
+    init_logger(log_handler=log_handler, nocolor=nocolor, stdout=dryrun, debug=debug, timestamp=timestamp)
 
     if not os.path.exists(snakefile):
         logger.error("Error: Snakefile \"{}\" not present.".format(snakefile))

File snakemake/executors.py

 
 from snakemake.jobs import Job
 from snakemake.shell import shell
-from snakemake.logging import logger
+import snakemake.logging as logging
 from snakemake.stats import Stats
 from snakemake.utils import format, Unformattable
 from snakemake.exceptions import print_exception, get_exception_origin
                 else:
                     yield f
 
-        def format_ruleitem(name, value):
-            return "" if not value else "\t{}: {}".format(name, value)
-
-        desc = list()
-        if not self.quiet:
-            if job.message:
-                desc.append(job.message)
-            else:
-                desc.append("{}rule {}:".format(self.rule_prefix(job), job.rule.name))
-                for name, value in (
-                    ("input", ", ".join(format_files(
-                        job, job.input, job.ruleio, job.dynamic_input))),
-                    ("output", ", ".join(format_files(
-                        job, job.output, job.ruleio,
-                        job.dynamic_output))),
-                    ("log", job.log),
-                    ("reason",
-                        self.dag.reason(job) if self.printreason else None)):
-                    if value:
-                        desc.append(format_ruleitem(name, value))
-                priority = self.dag.priority(job)
-                if priority > 1:
-                    desc.append(format_ruleitem(
-                        "priority", "highest"
-                        if priority == Job.HIGHEST_PRIORITY
-                        else priority))
-                if self.printthreads and job.threads > 1:
-                    desc.append(format_ruleitem("threads", job.threads))
-        if self.printshellcmds and job.shellcmd:
-            desc.append(job.shellcmd)
-        if desc:
-            logger.info("\n".join(desc))
-            if job.dynamic_output:
-                logger.warning("Subsequent jobs will be added dynamically "
+        priority = self.dag.priority(job)
+        logger.job_info(
+            msg=job.message,
+            name=job.rule.name,
+            local=self.workflow.is_local(job.rule),
+            input=list(format_files(job, job.input, job.ruleio, job.dynamic_input))),
+            output=list(format_files(job, job.output, job.ruleio, job.dynamic_output)),
+            log=job.log,
+            reason=self.dag.reason(job),
+            priority="highest" if priority == Job.HIGHEST_PRIORITY else priority,
+            threads=job.threads,
+            shellcmd=job.shellcmd)
+
+        if job.dynamic_output:
+            logger.info(
+                    "Subsequent jobs will be added dynamically "
                     "depending on the output of this rule")
 
     def finish_job(self, job):

File snakemake/logging.py

             message.append(self.RESET_SEQ)
         return "".join(message)
 
-logger = logging.getLogger(__name__)
+
+
+logger = Logger()
+stream_handler = None
 handler = None
 
 
-def init_logger(nocolor=False, stdout=False, debug=False, timestamp=False):
+class Logger:
+    def __init__(self):
+        self.logger = logging.getLogger(__name__)
+
+    def info(self, msg):
+        handler(dict(level="info", msg=msg))
+
+    def debug(self, msg):
+        handler(dict(level="debug", msg=msg))
+
+    def critical(self, msg):
+        handler(dict(level="critical", msg=msg))
+
+    def progress(self, count, total):
+        handler(dict(level="progress", count=count, total=total))
+
+    def job_info(self, **msg):
+        msg["level"] = "job_info"
+        handler(msg)
+    
+
+def quiet_console_handler(msg):
+    level = msg["level"]
+    if level == "info":
+        logger.warning(msg["msg"])
+    elif level == "critical":
+        logger.critical(msg["msg"])
+    elif level == "debug":
+        logger.debug(msg["msg"])
+
+
+def console_handler(msg):
+    def job_info(msg):
+        def format_item(item, omit=None, valueformat=str):
+            value = msg[item]
+            if value != omit:
+                return "\t{}: {}".format(item, valueformat(value))
+                
+        yield "{}rule {}:".format("local" if msg["local"] else "", msg["name"])
+        for item in "input output".split():
+            yield format_item(item, omit=[], ", ".join)
+        for item in "log reason".split():
+            yield format_item(item, omit="")
+        for item in "priority threads".split():
+            yield format_item(item, omit=1)
+        
+    quiet_console_handler(msg)
+    if level == "progress":
+        done = msg["done"]
+        total = msg["total"]
+        logger.info("{} of {} steps ({:.0%}) done".format(done, total, done / total))
+    elif level == "job_info":
+        if "msg" in msg:
+            logger.info(msg["msg"])
+        else:
+            logger.info("\n".join(job_info(msg)))
+
+
+def init_logger(log_handler=console_handler, nocolor=False, stdout=False, debug=False, timestamp=False):
     global logger
+    global stream_handler
     global handler
-    if handler:
-        logger.removeHandler(handler)
-    handler = ColorizingStreamHandler(
+    handler = log_handler
+    if stream_handler:
+        logger.removeHandler(stream_handler)
+    stream_handler = ColorizingStreamHandler(
         nocolor=nocolor, stream=sys.stdout if stdout else sys.stderr,
         timestamp=timestamp
     )
-    logger.addHandler(handler)
-    logger.setLevel(logging.DEBUG if debug else logging.INFO)
+    logger.logger.addHandler(stream_handler)
+    logger.logger.setLevel(logging.DEBUG if debug else logging.INFO)
+
 
 init_logger()

File snakemake/scheduler.py

 
 from snakemake.executors import DryrunExecutor, TouchExecutor
 from snakemake.executors import ClusterExecutor, CPUExecutor
-from snakemake.logging import logger
+import snakemake.logging as logging
 
 __author__ = "Johannes Köster"
 
 
     def progress(self):
         """ Display the progress. """
-        logger.info("{} of {} steps ({:.0%}) done".format(self.finished_jobs,
-            len(self.dag), self.finished_jobs / len(self.dag)))
+        logger.progress(self.finished_jobs, len(self.dag))
 
 
 def cumsum(iterable, zero=[0]):