diff options
| -rw-r--r-- | changes/feature_3504_add_log_silencer | 1 | ||||
| -rw-r--r-- | src/leap/bitmask/app.py | 11 | ||||
| -rw-r--r-- | src/leap/bitmask/util/leap_log_handler.py | 3 | ||||
| -rw-r--r-- | src/leap/bitmask/util/log_silencer.py | 95 | 
4 files changed, 108 insertions, 2 deletions
| diff --git a/changes/feature_3504_add_log_silencer b/changes/feature_3504_add_log_silencer new file mode 100644 index 00000000..7c551162 --- /dev/null +++ b/changes/feature_3504_add_log_silencer @@ -0,0 +1 @@ +  o Allow to selectively silence logs from different leap components. Closes: #3504 diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 6ffa1d25..0dce5e61 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -25,6 +25,7 @@ from functools import partial  from PySide import QtCore, QtGui  from leap.bitmask.util import leap_argparse +from leap.bitmask.util import log_silencer  from leap.bitmask.util.leap_log_handler import LeapLogHandler  from leap.bitmask.util.streamtologger import StreamToLogger  from leap.common.events import server as event_server @@ -51,7 +52,7 @@ def install_qtreactor(logger):      logger.debug("Qt4 reactor installed") -def add_logger_handlers(debug=False, logfile=None): +def add_logger_handlers(debug=False, logfile=None, standalone=False):      """      Create the logger and attach the handlers. @@ -71,6 +72,7 @@ def add_logger_handlers(debug=False, logfile=None):      # Create logger and formatter      logger = logging.getLogger(name='leap')      logger.setLevel(level) +      log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'      formatter = logging.Formatter(log_format) @@ -78,12 +80,16 @@ def add_logger_handlers(debug=False, logfile=None):      console = logging.StreamHandler()      console.setLevel(level)      console.setFormatter(formatter) + +    silencer = log_silencer.SelectiveSilencerFilter(standalone=standalone) +    console.addFilter(silencer)      logger.addHandler(console)      logger.debug('Console handler plugged!')      # LEAP custom handler      leap_handler = LeapLogHandler()      leap_handler.setLevel(level) +    leap_handler.addFilter(silencer)      logger.addHandler(leap_handler)      logger.debug('Leap handler plugged!') @@ -93,6 +99,7 @@ def add_logger_handlers(debug=False, logfile=None):          fileh = logging.FileHandler(logfile)          fileh.setLevel(logging.DEBUG)          fileh.setFormatter(formatter) +        fileh.addFilter(silencer)          logger.addHandler(fileh)          logger.debug('File handler plugged!') @@ -155,7 +162,7 @@ def main():      # pylint: avoid unused import      assert(locale_rc) -    logger = add_logger_handlers(debug, logfile) +    logger = add_logger_handlers(debug, logfile, standalone)      replace_stdout_stderr_with_logging(logger)      if not we_are_the_one_and_only(): diff --git a/src/leap/bitmask/util/leap_log_handler.py b/src/leap/bitmask/util/leap_log_handler.py index 9adb21a5..98924c12 100644 --- a/src/leap/bitmask/util/leap_log_handler.py +++ b/src/leap/bitmask/util/leap_log_handler.py @@ -90,6 +90,9 @@ class HandlerAdapter(object):      def setLevel(self, *args, **kwargs):          return self._handler.setLevel(*args, **kwargs) +    def addFilter(self, *args, **kwargs): +        return self._handler.addFilter(*args, **kwargs) +      def handle(self, *args, **kwargs):          return self._handler.handle(*args, **kwargs) diff --git a/src/leap/bitmask/util/log_silencer.py b/src/leap/bitmask/util/log_silencer.py new file mode 100644 index 00000000..09aa2cff --- /dev/null +++ b/src/leap/bitmask/util/log_silencer.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# log_silencer.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +""" +Filter for leap logs. +""" +import logging +import os +import re + +from leap.common.config import get_path_prefix + + +class SelectiveSilencerFilter(logging.Filter): +    """ +    Configurable filter for root leap logger. + +    If you want to ignore components from the logging, just add them, +    one by line, to ~/.config/leap/leap.dev.conf +    """ +    # TODO we can augment this by properly parsing the log-silencer file +    # and having different sections: ignore, levels, ... + +    # TODO use ConfigParser to unify sections [log-ignore] [log-debug] etc + +    CONFIG_NAME = "leap.dev.conf" + +    # Components to be completely silenced in the main bitmask logs. +    # You probably should think twice before adding a component to +    # the tuple below. Only very well tested components should go here, and +    # only in those cases in which we gain more from silencing them than from +    # having their logs into the main log file that the user will likely send +    # to us. +    SILENCER_RULES = ( +        'leap.common.events', +    ) + +    def __init__(self, standalone=False): +        """ +        Tries to load silencer rules from the default path, +        or load from the SILENCER_RULES tuple if not found. +        """ +        self.standalone = standalone +        self.rules = None +        if os.path.isfile(self._rules_path): +            self.rules = self._load_rules() +        if not self.rules: +            self.rules = self.SILENCER_RULES + +    @property +    def _rules_path(self): +        """ +        The configuration file for custom ignore rules. +        """ +        return os.path.join( +            get_path_prefix(standalone=self.standalone), +            "leap", self.CONFIG_NAME) + +    def _load_rules(self): +        """ +        Loads a list of paths to be ignored from the logging. +        """ +        lines = open(self._rules_path).readlines() +        return map(lambda line: re.sub('\s', '', line), +                   lines) + +    def filter(self, record): +        """ +        Implements the filter functionality for this Filter + +        :param record: the record to be examined +        :type record: logging.LogRecord +        :returns: a bool indicating whether the record should be logged or not. +        :rtype: bool +        """ +        if not self.rules: +            return True +        logger_path = record.name +        for path in self.rules: +            if logger_path.startswith(path): +                return False +        return True | 
