Index: client/utils/logging_utils.py |
diff --git a/appengine/swarming/swarming_bot/logging_utils.py b/client/utils/logging_utils.py |
similarity index 59% |
rename from appengine/swarming/swarming_bot/logging_utils.py |
rename to client/utils/logging_utils.py |
index efddb9c99c8da8360341115449ff09bc87aa0568..f44880e7277ec0110f823163748f1883e1480be2 100644 |
--- a/appengine/swarming/swarming_bot/logging_utils.py |
+++ b/client/utils/logging_utils.py |
@@ -1,16 +1,14 @@ |
-# Copyright 2014 The Swarming Authors. All rights reserved. |
-# Use of this source code is governed by the Apache v2.0 license that can be |
-# found in the LICENSE file. |
+# Copyright 2015 The Swarming Authors. All rights reserved. |
+# Use of this source code is governed under the Apache License, Version 2.0 that |
+# can be found in the LICENSE file. |
-"""Utility relating to logging. |
- |
-TODO(maruel): Merge buffering and output related code from client/utils/tools.py |
-in a single file. |
-""" |
+"""Utility relating to logging.""" |
+import argparse |
import codecs |
import logging |
import logging.handlers |
+import optparse |
import os |
import sys |
import tempfile |
@@ -58,6 +56,10 @@ else: # Not Windows. |
NoInheritRotatingFileHandler = logging.handlers.RotatingFileHandler |
+# Levels used for logging. |
+LEVELS = [logging.ERROR, logging.INFO, logging.DEBUG] |
+ |
+ |
class CaptureLogs(object): |
"""Captures all the logs in a context.""" |
def __init__(self, prefix, root=None): |
@@ -134,6 +136,11 @@ def prepare_logging(filename, root=None): |
Makes it log in UTC all the time. Prepare a rotating file based log. |
""" |
assert not find_stderr(root) |
+ # Other options are: |
+ # '%(levelname)5s %(relativeCreated)6d %(module)15s(%(lineno)3d): ' |
+ # '%(message)s' |
+ # or: |
+ # '%(asctime)s %(levelname)-8s %(module)15s(%(lineno)3d): %(message)s')) |
formatter = UTCFormatter( |
'%(process)d %(asctime)s: %(levelname)-5s %(message)s') |
Vadim Sh.
2015/07/15 18:46:38
consider also https://chromium.googlesource.com/in
|
@@ -153,7 +160,8 @@ def prepare_logging(filename, root=None): |
if filename: |
try: |
rotating_file = NoInheritRotatingFileHandler( |
- filename, maxBytes=10 * 1024 * 1024, backupCount=5) |
+ filename, maxBytes=10 * 1024 * 1024, backupCount=5, |
+ encoding='utf-8') |
rotating_file.setLevel(logging.DEBUG) |
rotating_file.setFormatter(formatter) |
logger.addHandler(rotating_file) |
@@ -166,3 +174,81 @@ def set_console_level(level, root=None): |
"""Reset the console (stderr) logging level.""" |
handler = find_stderr(root) |
handler.setLevel(level) |
+ |
+ |
+class OptionParserWithLogging(optparse.OptionParser): |
+ """Adds --verbose option.""" |
+ |
+ # Set to True to enable --log-file options. |
+ enable_log_file = True |
+ |
+ # Set in unit tests. |
+ logger_root = None |
+ |
+ def __init__(self, verbose=0, log_file=None, **kwargs): |
+ kwargs.setdefault('description', sys.modules['__main__'].__doc__) |
+ optparse.OptionParser.__init__(self, **kwargs) |
+ self.group_logging = optparse.OptionGroup(self, 'Logging') |
+ self.group_logging.add_option( |
+ '-v', '--verbose', |
+ action='count', |
+ default=verbose, |
+ help='Use multiple times to increase verbosity') |
+ if self.enable_log_file: |
+ self.group_logging.add_option( |
+ '-l', '--log-file', |
+ default=log_file, |
+ help='The name of the file to store rotating log details') |
+ self.group_logging.add_option( |
+ '--no-log', action='store_const', const='', dest='log_file', |
+ help='Disable log file') |
+ |
+ def parse_args(self, *args, **kwargs): |
+ # Make sure this group is always the last one. |
+ self.add_option_group(self.group_logging) |
+ |
+ options, args = optparse.OptionParser.parse_args(self, *args, **kwargs) |
+ prepare_logging(self.enable_log_file and options.log_file, self.logger_root) |
+ set_console_level( |
+ LEVELS[min(len(LEVELS) - 1, options.verbose)], self.logger_root) |
+ return options, args |
+ |
+ |
+class ArgumentParserWithLogging(argparse.ArgumentParser): |
+ """Adds --verbose option.""" |
+ |
+ # Set to True to enable --log-file options. |
+ enable_log_file = True |
+ |
+ def __init__(self, verbose=0, log_file=None, **kwargs): |
+ kwargs.setdefault('description', sys.modules['__main__'].__doc__) |
+ kwargs.setdefault('conflict_handler', 'resolve') |
+ self.__verbose = verbose |
+ self.__log_file = log_file |
+ super(ArgumentParserWithLogging, self).__init__(**kwargs) |
+ |
+ def _add_logging_group(self): |
+ group = self.add_argument_group('Logging') |
+ group.add_argument( |
+ '-v', '--verbose', |
+ action='count', |
+ default=self.__verbose, |
+ help='Use multiple times to increase verbosity') |
+ if self.enable_log_file: |
+ group.add_argument( |
+ '-l', '--log-file', |
+ default=self.__log_file, |
+ help='The name of the file to store rotating log details') |
+ group.add_argument( |
+ '--no-log', action='store_const', const='', dest='log_file', |
+ help='Disable log file') |
+ |
+ def parse_args(self, *args, **kwargs): |
+ # Make sure this group is always the last one. |
+ self._add_logging_group() |
+ |
+ args = super(ArgumentParserWithLogging, self).parse_args(*args, **kwargs) |
+ prepare_logging(self.enable_log_file and args.log_file, self.logger_root) |
+ set_console_level( |
+ LEVELS[min(len(LEVELS) - 1, args.verbose)], self.logger_root) |
+ return args |