diff mbox

[Branch,~linaro-validation/lava-tool/trunk] Rev 173: Improve global logging support

Message ID 20120322183110.21452.52279.launchpad@ackee.canonical.com
State Accepted
Headers show

Commit Message

Zygmunt Krynicki March 22, 2012, 6:31 p.m. UTC
Merge authors:
  Zygmunt Krynicki (zkrynicki)
Related merge proposals:
  https://code.launchpad.net/~zkrynicki/lava-tool/next/+merge/85586
  proposed by: Zygmunt Krynicki (zkrynicki)
------------------------------------------------------------
revno: 173 [merge]
committer: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
branch nick: release
timestamp: Thu 2012-03-22 19:03:03 +0100
message:
  Improve global logging support
modified:
  lava/tool/command.py
  lava/tool/dispatcher.py
  lava/tool/main.py
  lava_tool/interface.py


--
lp:lava-tool
https://code.launchpad.net/~linaro-validation/lava-tool/trunk

You are subscribed to branch lp:lava-tool.
To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-tool/trunk/+edit-subscription
diff mbox

Patch

=== modified file 'lava/tool/command.py'
--- lava/tool/command.py	2012-03-19 16:07:55 +0000
+++ lava/tool/command.py	2012-03-22 18:03:03 +0000
@@ -112,7 +112,7 @@ 
         pass
 
 
-class SubCommand(Command):
+class CommandGroup(Command):
     """
     Base class for all command sub-command hubs.
 
@@ -120,7 +120,7 @@ 
     options that can be freely extended, just like the top-level lava-tool
     command.
 
-    For example, a SubCommand 'actions' will load additional commands from a
+    For example, a CommandGroup 'actions' will load additional commands from a
     the 'lava.actions' namespace. For the end user it will be available as::
 
         $ lava-tool foo actions xxx
@@ -161,3 +161,6 @@ 
         if namespace is not None:
             dispatcher.import_commands(namespace)
         parser.set_defaults(dispatcher=dispatcher)
+
+
+SubCommand = CommandGroup

=== modified file 'lava/tool/dispatcher.py'
--- lava/tool/dispatcher.py	2012-03-19 16:08:08 +0000
+++ lava/tool/dispatcher.py	2012-03-22 18:03:03 +0000
@@ -54,10 +54,13 @@ 
         dispatcher instance.
         """
         parser_args = dict(add_help=True)
+        # Set description based on class description
         if cls.description is not None:
             parser_args['description'] = cls.description
+        # Set the epilog based on class epilog
         if cls.epilog is not None:
             parser_args['epilog'] = cls.epilog
+        # Return the fresh parser
         return argparse.ArgumentParser(**parser_args)
 
     def import_commands(self, entrypoint_name):
@@ -86,13 +89,15 @@ 
             command_cls.get_name(),
             help=command_cls.get_help(),
             epilog=command_cls.get_epilog())
-        from lava.tool.command import SubCommand
-        if issubclass(command_cls, SubCommand):
-            # Handle SubCommand somewhat different. Instead of calling
+        from lava.tool.command import CommandGroup 
+        if issubclass(command_cls, CommandGroup):
+            # Handle CommandGroup somewhat different. Instead of calling
             # register_arguments we call register_subcommands
             command_cls.register_subcommands(sub_parser)
+            # Let's also call register arguments in case we need both
+            command_cls.register_arguments(sub_parser)
         else:
-            # Handle plain commands easily by recording their commands in the
+            # Handle plain commands by recording their commands in the
             # dedicated sub-parser we've crated for them.
             command_cls.register_arguments(sub_parser)
             # In addition, since we don't want to require all sub-classes of
@@ -105,6 +110,11 @@ 
         # Make sure the sub-parser knows about this dispatcher
         sub_parser.set_defaults(dispatcher=self)
 
+    def _adjust_logging_level(self, args):
+        """
+        Adjust logging level after seeing the initial arguments
+        """
+
     def dispatch(self, raw_args=None):
         """
         Dispatch a command with the specified arguments.
@@ -113,6 +123,8 @@ 
         """
         # First parse whatever input arguments we've got
         args = self.parser.parse_args(raw_args)
+        # Adjust logging level after seeing arguments
+        self._adjust_logging_level(args)
         # Then look up the command class and construct it with the parser it
         # belongs to and the parsed arguments.
         command = args.command_cls(args.parser, args)

=== modified file 'lava/tool/main.py'
--- lava/tool/main.py	2012-03-13 18:22:16 +0000
+++ lava/tool/main.py	2012-03-22 18:03:03 +0000
@@ -23,6 +23,9 @@ 
 Implementation of the `lava` shell command.
 """
 
+import logging
+import sys
+
 from lava.tool.dispatcher import Dispatcher
 
 
@@ -37,5 +40,93 @@ 
     """
 
     def __init__(self):
+        # Call this early so that we don't get logging.basicConfig
+        # being called by accident. Otherwise we'd have to
+        # purge all loggers from the root logger and that sucks
+        self.setup_logging()
+        # Initialize the base dispatcher
         super(LavaDispatcher, self).__init__()
+        # And import the non-flat namespace commands
         self.import_commands('lava.commands')
+
+    @classmethod
+    def construct_parser(cls):
+        """
+        Construct a parser for this dispatcher.
+
+        This is only used if the parser is not provided by the parent
+        dispatcher instance.
+        """
+        # Construct a basic parser
+        parser = super(LavaDispatcher, cls).construct_parser()
+        # Add the --verbose flag
+        parser.add_argument(
+            "-v", "--verbose",
+            default=False,
+            action="store_true",
+            help="Be more verbose (displays more messages globally)")
+        # Add the --debug flag
+        parser.add_argument(
+            "-D", "--debug",
+            action="store_true",
+            default=False,
+            help="Enable debugging on all loggers")
+        # Add the --trace flag
+        parser.add_argument(
+            "-T", "--trace",
+            action="append",
+            default=[],
+            help="Enable debugging of the specified logger, can be specified multiple times")
+        # Return the improved parser
+        return parser 
+
+    def setup_logging(self):
+        """
+        Setup logging for the root dispatcher
+        """
+        # Enable warning/error message handler
+        class OnlyProblemsFilter(logging.Filterer):
+            def filter(self, record):
+                if record.levelno >= logging.WARN:
+                    return 1
+                return 0
+        err_handler = logging.StreamHandler(sys.stderr)
+        err_handler.setLevel(logging.WARN)
+        err_handler.setFormatter(
+            logging.Formatter("%(levelname)s: %(message)s"))
+        err_handler.addFilter(OnlyProblemsFilter())
+        logging.getLogger().addHandler(err_handler)
+        # Enable the debug handler
+        class DebugFilter(logging.Filter):
+            def filter(self, record):
+                if record.levelno == logging.DEBUG:
+                    return 1
+                return 0
+        dbg_handler = logging.StreamHandler(sys.stderr)
+        dbg_handler.setLevel(logging.DEBUG)
+        dbg_handler.setFormatter(
+            logging.Formatter("%(levelname)s %(name)s: %(message)s"))
+        dbg_handler.addFilter(DebugFilter())
+        logging.getLogger().addHandler(dbg_handler)
+
+    def _adjust_logging_level(self, args):
+        # Enable verbose message handler
+        if args.verbose:
+            logging.getLogger().setLevel(logging.INFO)
+            class OnlyInfoFilter(logging.Filterer):
+                def filter(self, record):
+                    if record.levelno == logging.INFO:
+                        return 1
+                    return 0
+            msg_handler = logging.StreamHandler(sys.stdout)
+            msg_handler.setLevel(logging.INFO)
+            msg_handler.setFormatter(
+                logging.Formatter("%(message)s"))
+            msg_handler.addFilter(OnlyInfoFilter())
+            logging.getLogger().addHandler(msg_handler)
+        # Enable debugging 
+        if args.debug:
+            logging.getLogger().setLevel(logging.DEBUG)
+        # Enable trace loggers
+        for name in args.trace:
+            logging.getLogger(name).setLevel(logging.DEBUG)

=== modified file 'lava_tool/interface.py'
--- lava_tool/interface.py	2012-03-13 16:30:24 +0000
+++ lava_tool/interface.py	2012-03-22 18:03:03 +0000
@@ -21,4 +21,4 @@ 
 """
 
 from lava.tool.errors import CommandError as LavaCommandError
-from lava.tool.command import Command, SubCommand
+from lava.tool.command import Command, CommandGroup as SubCommand