Example #1
0
    def test_remote_logging_bind_simple(self):
        """
        Process Parent receives logs from child process
        """
        # Configure the log in the parent so that all logs received from the child
        # goes to a dedicated file from which we can count the number of messages
        # produced by the child
        tmpdir = tempfile.mkdtemp(suffix="tmp",
                                  prefix=BXIRemoteLoggerTest.__name__)
        all = os.path.join(tmpdir, 'all.bxilog')
        child = os.path.join(tmpdir, 'child.bxilog')
        parent_config = {
            'handlers': ['all', 'child'],
            'all': {
                'module': 'bxi.base.log.file_handler',
                'filters': ':lowest',
                'path': all,
                'append': True,
            },
            'child': {
                'module': 'bxi.base.log.file_handler',
                'filters': ':off,%s:lowest' % LOGGER_CMD,
                'path': child,
                'append': True,
            }
        }
        bxilog.set_config(configobj.ConfigObj(parent_config))
        print("Logging output: all: %s, child: %s" % (all, child))
        url = 'ipc://%s/rh-cfg.zock' % tmpdir
        logs_nb = 25
        full_cmd_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), LOGGER_CMD)
        logger_output_file = os.path.join(
            tmpdir,
            os.path.splitext(LOGGER_CMD)[0] + '.bxilog')

        args = [
            full_cmd_path, logger_output_file, url, 'False', '1',
            str(logs_nb)
        ]
        bxilog.out("Executing '%s': it must produce %d logs", ' '.join(args),
                   logs_nb)
        popen = subprocess.Popen(args)
        bxilog.out("Starting logs reception thread on %s", url)
        receiver = remote_receiver.RemoteReceiver([url], bind=True)
        receiver.start()
        bxilog.out("Waiting for the child termination")
        popen.wait()
        rc = popen.returncode
        bxilog.out("Child exited with return code %s", rc)
        self.assertEquals(rc, logs_nb)
        # Wait a bit for the logs to be processed
        time.sleep(1)
        bxilog.out("Stopping the receiver")
        receiver.stop(True)
        bxilog.out("Flushing bxilog")
        bxilog.flush()
        with open(child) as file_:
            lines = file_.readlines()
        self.assertEquals(len(lines), logs_nb)
Example #2
0
    def test_config_file(self):
        """Test logging with configuration items"""

        orig_size = os.stat(FILENAME).st_size if os.path.exists(
            FILENAME) else 0

        conf = {
            'handlers': ['out', 'null'],
            'setsighandler': True,
            'out': {
                'module': 'bxi.base.log.file_handler',
                'filters': ':output,foo:debug,foo.bar:trace',
                'path': FILENAME,
                'append': True
            },
            'null': {
                'module': 'bxi.base.log.null_handler',
                'filters': ':off,foo:fine,foo.bar:debug',
            },
        }
        bxilog.set_config(configobj.ConfigObj(conf))
        # It is required to initialize the library for the configuration to be used
        bxilog.init()

        foo = bxilog.getLogger('foo')
        self.assertEqual(foo.level, bxilog.FINE)
        bar = bxilog.getLogger('foo.bar')
        self.assertEqual(bar.level, bxilog.TRACE)
        any = bxilog.getLogger('bebopalula')
        self.assertEqual(any.level, bxilog.OUTPUT)

        any.info('This message must not appear in file %s', FILENAME)
        bxilog.flush()
        newsize = os.stat(FILENAME).st_size
        self.assertEquals(newsize, orig_size)
        bar.lowest('This message must also not appear in file %s', FILENAME)
        bxilog.flush()
        newsize = os.stat(FILENAME).st_size
        self.assertEquals(newsize, orig_size)
        foo.fine('This message must not appear in file %s', FILENAME)
        bxilog.flush()
        newsize = os.stat(FILENAME).st_size
        self.assertEquals(newsize, orig_size)

        self._check_log_produced(FILENAME, any.output,
                                 'This message must appear in file %s',
                                 FILENAME)
        self._check_log_produced(FILENAME, bar.trace,
                                 'This message must also appear in file %s',
                                 FILENAME)
        self._check_log_produced(FILENAME, foo.debug,
                                 'This message must also appear in file %s',
                                 FILENAME)
        self._check_log_produced(FILENAME, bxilog.output,
                                 "This message must also appear in file %s",
                                 FILENAME)
Example #3
0
    def setUp(self):
        unittest.TestCase.setUp(self)
        if not hasattr(self, 'bxilog_config'):
            self.bxilog_config = bxilog.get_config()

        bxilog.set_config(self.bxilog_config)

        try:
            self.bxiconfigdir = tempfile.mkdtemp()
        except KeyError:
            pass
Example #4
0
def main(file_out, url, bind, sync_nb, logs_nb):
    config = {
        'handlers': ['file', 'remote'],
        'remote': {
            'module': 'bxi.base.log.remote_handler',
            'filters': ':all',
            'url': url,
            'bind': bind,
        },
        'file': {
            'module': 'bxi.base.log.file_handler',
            'filters': ':all',
            'path': file_out,
            'append': True,
        }
    }
    bxilog.set_config(config)
    nb = 0
    nb += _do_log(0, logs_nb / 2)
    bxilog.cleanup()
    bxilog.set_config(config)
    nb += _do_log(logs_nb / 2, logs_nb)

    return nb
Example #5
0
def _configure_log(parser):
    """
    Configure the bxilog options for the given parser

    @param[inout] parser the parser to add options to
    """
    def _add_common(target_parser):
        """
        Add common options to the given target_parser

        @param[inout] target_parser the target_parser to add options to
        """
        # Warning: do not introduce --log-STUFF unless STUFF is actually the name
        # of a bxilog handler.
        group = target_parser.add_argument_group('BXI Log options')
        group.add_argument("--loglevels",
                           mustbeprinted=False,
                           action=LogLevelsAction,
                           help="Displays all log levels and exit.")

        group.add_argument(
            "--logoutput-default-config",
            dest='output_default_logcfg',
            action='store_true',
            mustbeprinted=False,
            help="Output the default logging configuration and exit.")

        group.add_argument(
            "--logcfgfile",
            mustbeprinted=False,
            metavar='logcfgfile',
            default=None,
            help="Logging configuration file. "
            " Use '--logoutput-default-config' to customize one to your "
            "own needs. Value: %(default)s.")
        return group

    def _add_others(target_parser, args, group, config):
        """
        Add remaining options to the given target_parser

        @param[inout] target_parser the target parser to add options to
        @param[in] args the current set of parsed arguments
        @param[in] group the group in which the arguments must be set
        @param[in] config the configuration
        """
        sections = find_logconfigs(bxilog_consolehandler.__name__, config)
        if len(sections) > 1:
            target_parser.error("Multiple instances of module %s is "
                                "currently unsupported. Configuration: %s " %
                                (bxilog_consolehandler.__name__, config))
        if len(sections) == 0:
            console_handler = None
        else:
            console_handler = sections[0]
            console_section = config[console_handler]
            if 'filters' not in console_section:
                target_parser.error(
                    "Bad logging configuration: 'filters' is missing "
                    "in section '%s' of config %s" % (console_handler, config))
            default = console_section['filters']
            group.add_argument(
                "-l",
                "--log-%s-filters" % console_handler,
                mustbeprinted=False,
                metavar='log-%s-filters' % console_handler,
                envvar='BXILOG_%s_FILTERS' % console_handler.upper(),
                default=default,
                help="Define the logging filters for the "
                " %s handler " % console_handler + "Value: '%(default)s'. "
                "Logging filters are defined by the following "
                "format: logger_name_prefix:level[,prefix:level]*")

            group.add_argument("--quiet",
                               action='store_true',
                               mustbeprinted=True,
                               help="Set log console filter to off.")

            if 'colors' not in console_section:
                default = DEFAULT_CONSOLE_COLORS
            else:
                default = console_section['colors']

            group.add_argument(
                "--log-%s-colors" % console_handler,
                mustbeprinted=False,
                metavar='log-%s-colors' % console_handler,
                envvar='BXILOG_%s_COLORS' % console_handler.upper(),
                default=default,
                choices=list(bxilog_consolehandler.COLORS),
                help="Define the logging colors for the %s handler " %
                console_handler + "Value: '%(default)s'." +
                " choices=%s. " % list(bxilog_consolehandler.COLORS))

        sections = find_logconfigs(bxilog_filehandler.__name__, config)
        for section in sections:
            conf = config[section]
            if 'filters' not in conf:
                target_parser.error(
                    "Bad logging configuration: 'filters' is missing "
                    "in section '%s' of config %s" % (section, config))
            default = conf['filters']
            if console_handler is not None:
                auto_help_msg = "If set to '%s', " % bxilog_filehandler.FILTERS_AUTO + \
                                "filters are automatically computed to " + \
                                "provide two levels more details than handler '%s' " % \
                                console_handler + \
                                "and at least error levels and above. "
            else:
                auto_help_msg = ""
            group.add_argument(
                "--log-%s-filters" % section,
                metavar='log-%s-filters' % section,
                mustbeprinted=False,
                envvar='BXILOG_%s_FILTERS' % section.upper(),
                default=default,
                help="Define the logging filters for the "
                "%s handler " % section +
                "of the default logging configuration. " + auto_help_msg +
                "The format is the one defined by "
                "console_filters option. Value: '%(default)s'. ")

            if 'path' not in conf:
                target_parser.error(
                    "Bad logging configuration: 'path' is missing "
                    "in section '%s' of config %s" % (section, config))
            default = conf['path']
            group.add_argument(
                "--log-%s-path" % section,
                metavar='PATH',
                envvar='BXILOGPATH',
                mustbeprinted=False,
                default=default,
                help="Define the destination file for the %s handler " %
                section + "Value: %(default)s")

            if 'append' not in conf:
                default = True
            else:
                default = conf['append']
            group.add_argument(
                "--log-%s-append" % section,
                metavar='bool',
                mustbeprinted=False,
                default=default,
                help="When true, append to destination path of handler "
                "%s, instead of owerwriting. " % section +
                "Value: %(default)s")

    def _override_logconfig(config, known_args, parser):
        """
        Override the given logging configuration with given known_args

        @param[inout] config the logging configuration
        @param[in] know_args known arguments
        """
        def _override_kv(option, key, config, args):
            """
            Override the config[key] value by the one given by args[option]

            @param[in] option the option name (long format)
            @param[in] key the key in the config file for the current handler
            @param[inout] config the configuration
            @param[in] known_args the currently known arguments
            """
            # option has the following format: --log-handler-key=value
            if option.endswith(key):
                handler_name = option[len('log_'):option.index(key) - 1]
                assert handler_name in config
                # replace in config
                #                 print("Overriding: %s -> %s[%s]=%s" %
                #                       (option, handler_name, key, args[option]))
                config[handler_name][key] = args[option]

        args = vars(known_args)

        for option in args:
            _override_kv(option, 'filters', config, args)
            _override_kv(option, 'colors', config, args)
            _override_kv(option, 'path', config, args)
            _override_kv(option, 'append', config, args)

            # if --quiet option is provided, set output log level for console handlers
            # to minimal settings so that nothing is printed on stdout (nothing change
            # for stderr).
            if option is "quiet":
                if args[option] is True:
                    sections = find_logconfigs(bxilog_consolehandler.__name__,
                                               config)
                    if len(sections) > 1:
                        parser.error(
                            "Multiple instances of module %s is "
                            "currently unsupported. Configuration: %s " %
                            (bxilog_consolehandler.__name__, config))
                        if len(sections) == 1:
                            option = "log_console_filters"
                        key = 'filters'
                        handler_name = option[len('log_'):option.index(key) -
                                              1]
                        args[option] = ":%s" % config[handler_name][
                            "stderr_level"]
                        _override_kv(option, key, config, args)

    parser.add_argument('--help-logs',
                        action=_LoggedHelpAction,
                        default=posless.SUPPRESS,
                        help=_('Show detailed logging options and exit'))

    group = _add_common(parser)

    known_args = parser.get_known_args()[0]

    if known_args is None:
        return

    baseconf = {
        'handlers': ['console', 'file'],
        'setsighandler': True,
        'console': {
            'module': bxilog_consolehandler.__name__,
            'filters': ':output',
            'stderr_level': 'WARNING',
            'colors': '216_dark',
        },
        'file': {
            'module': bxilog_filehandler.__name__,
            'filters': 'auto',
            'path':
            os.path.join(tempfile.gettempdir(), '%(prog)s') + '.bxilog',
            'append': True,
        }
    }

    if known_args.output_default_logcfg:
        config = configobj.ConfigObj(infile=baseconf, interpolation=False)
        for line in config.write():
            print(line)
        sys.exit(0)

    if known_args.logcfgfile is None:

        # The Environment and command line does not define a specific file
        # Use the one from the configuration
        default_logcfgfile = getdefaultvalue(parser, ['Defaults'],
                                             BXILOG_DEFAULT_CONFIGFILE_KEY,
                                             None)
        parser.set_defaults(logcfgfile=default_logcfgfile)

        infile = default_logcfgfile
        if infile is None:
            # Default case: no logging configuration given and no file found by default
            infile = baseconf
            logcfg_msg = "No logging configuration file given, using default."
        else:
            if not os.path.isabs(infile):
                # Find the absolute path from config-file...
                config_dir = os.path.dirname(parser.known_config_file)
                infile = os.path.join(config_dir, infile)

            if not os.path.exists(infile):
                parser.error("Logging configuration file "
                             "not found: %s. " % infile +
                             "Check your configuration "
                             "from file: %s" % parser.known_config_file)
            logcfg_msg = "Using logging configuration file '%s' specified by '%s'" %\
                         (infile, parser.known_config_file)

        config = configobj.ConfigObj(infile=infile, interpolation=False)
    elif not os.path.exists(known_args.logcfgfile):
        parser.error("For option logcfgfile, provided file not found: %s" %
                     known_args.logcfgfile)
    else:
        config = configobj.ConfigObj(infile=known_args.logcfgfile,
                                     interpolation=False)
        logcfg_msg = "Using logging configuration file '%s' specified by command line" %\
                     known_args.logcfgfile

    _add_others(parser, known_args, group, config)

    known_args = parser.get_known_args()[0]

    _override_logconfig(config, known_args, parser)

    logging.captureWarnings(True)
    if logging.is_configured():
        logging.info("Reconfiguration of the logging system")
        logging.cleanup()
    logging.set_config(config)
    if parser.known_config_file is not None:
        _LOGGER.info("Configuration based on '%s': %s",
                     parser.known_config_file, parser.config)
    else:
        _LOGGER.info("No configuration file found, using default values: %s",
                     parser.config)
    _LOGGER.debug(logcfg_msg)