From 4b3f00962cbce75f5120c0d370e03c3007dfe92d Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 2 Sep 2013 13:40:17 +0200 Subject: Add a selective filter for leap logs. Closes: #3504 --- changes/feature_3504_add_log_silencer | 1 + src/leap/bitmask/app.py | 11 +++- src/leap/bitmask/util/leap_log_handler.py | 3 + src/leap/bitmask/util/log_silencer.py | 95 +++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 changes/feature_3504_add_log_silencer create mode 100644 src/leap/bitmask/util/log_silencer.py 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 . +""" +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 -- cgit v1.2.3