diff options
-rw-r--r-- | sos/__init__.py | 61 | ||||
-rw-r--r-- | sos/utilities.py | 28 |
2 files changed, 89 insertions, 0 deletions
diff --git a/sos/__init__.py b/sos/__init__.py index 8de4bfd8..013e3e4d 100644 --- a/sos/__init__.py +++ b/sos/__init__.py @@ -16,8 +16,10 @@ gettext to internationalize messages. """ __version__ = "3.9" +import logging import six import sys +import tempfile from argparse import ArgumentParser @@ -27,6 +29,7 @@ else: from ConfigParser import ConfigParser, ParsingError, Error from sos.options import SoSOptions, SosListOption +from sos.utilities import TempFileUtil class SoSComponent(): @@ -51,6 +54,7 @@ class SoSComponent(): desc = 'unset' arg_defaults = {} + configure_logging = True _arg_defaults = { "quiet": False, @@ -66,6 +70,11 @@ class SoSComponent(): # update args from component's arg_defaults defintion self._arg_defaults.update(self.arg_defaults) self.opts = self.load_options() + if self.configure_logging: + tmpdir = self.opts.tmp_dir or tempfile.gettempdir() + self.tmpdir = tempfile.mkdtemp(prefix="sos.", dir=tmpdir) + self.tempfile_util = TempFileUtil(self.tmpdir) + self._setup_logging() @classmethod def add_parser_options(cls, parser): @@ -83,6 +92,58 @@ class SoSComponent(): opts.merge(cmdopts) return opts + def _setup_logging(self): + """Creates the log handler that shall be used by all components and any + and all related bits to those components that need to log either to the + console or to the log file for that run of sos. + """ + # main soslog + self.soslog = logging.getLogger('sos') + self.soslog.setLevel(logging.DEBUG) + self.sos_log_file = self.get_temp_file() + flog = logging.StreamHandler(self.sos_log_file) + flog.setFormatter(logging.Formatter( + '%(asctime)s %(levelname)s: %(message)s')) + flog.setLevel(logging.INFO) + self.soslog.addHandler(flog) + + if not self.opts.quiet: + console = logging.StreamHandler(sys.stdout) + console.setFormatter(logging.Formatter('%(message)s')) + if self.opts.verbosity and self.opts.verbosity > 1: + console.setLevel(logging.DEBUG) + flog.setLevel(logging.DEBUG) + elif self.opts.verbosity and self.opts.verbosity > 0: + console.setLevel(logging.INFO) + flog.setLevel(logging.DEBUG) + else: + console.setLevel(logging.WARNING) + self.soslog.addHandler(console) + # log ERROR or higher logs to stderr instead + console_err = logging.StreamHandler(sys.stderr) + console_err.setFormatter(logging.Formatter('%(message)s')) + console_err.setLevel(logging.ERROR) + self.soslog.addHandler(console_err) + + # ui log + self.ui_log = logging.getLogger('sos_ui') + self.ui_log.setLevel(logging.INFO) + self.sos_ui_log_file = self.get_temp_file() + ui_fhandler = logging.StreamHandler(self.sos_ui_log_file) + ui_fhandler.setFormatter(logging.Formatter( + '%(asctime)s %(levelname)s: %(message)s')) + + self.ui_log.addHandler(ui_fhandler) + + if not self.opts.quiet: + ui_console = logging.StreamHandler(sys.stdout) + ui_console.setFormatter(logging.Formatter('%(message)s')) + ui_console.setLevel(logging.INFO) + self.ui_log.addHandler(ui_console) + + def get_temp_file(self): + return self.tempfile_util.new() + class SoS(): """Main entrypoint for sos from the command line diff --git a/sos/utilities.py b/sos/utilities.py index 851b7715..5ac90be9 100644 --- a/sos/utilities.py +++ b/sos/utilities.py @@ -17,6 +17,7 @@ import fnmatch import errno import shlex import glob +import tempfile import threading import time import gettext @@ -318,6 +319,33 @@ class ImporterHelper(object): return plugins +class TempFileUtil(): + + def __init__(self, tmp_dir): + self.tmp_dir = tmp_dir + self.files = [] + + def new(self): + fd, fname = tempfile.mkstemp(dir=self.tmp_dir) + # avoid TOCTOU race by using os.fdopen() + fobj = os.fdopen(fd, 'w+') + self.files.append((fname, fobj)) + return fobj + + def clean(self): + for fname, f in self.files: + try: + f.flush() + f.close() + except Exception: + pass + try: + os.unlink(fname) + except Exception: + pass + self.files = [] + + class SoSTimeoutError(OSError): pass |