Beispiel #1
0
 def __init__(self):
     super(ConsoleStatusReporter, self).__init__()
     self._last_datapoint = None
     self.__streams_redirected = False
     self.logger_handlers = []
     self.orig_streams = {}
     self.temp_stream = StringIONotifying(self.log_updated)
     self.screen_size = (140, 35)
     self.disabled = False
     self.console = None
     self.executor_widgets = []
     self.screen = DummyScreen(self.screen_size[0], self.screen_size[1])
Beispiel #2
0
 def _get_screen(self):
     screen_type = self._get_screen_type()
     if screen_type == "console":
         return ConsoleScreen()
     elif screen_type == "gui":
         return GUIScreen()
     else:
         cols = self.settings.get('dummy-cols', self.screen_size[0])
         rows = self.settings.get('dummy-rows', self.screen_size[1])
         return DummyScreen(cols, rows)
Beispiel #3
0
 def __init__(self):
     super(ConsoleStatusReporter, self).__init__()
     self._last_datapoint = None
     self.__streams_redirected = False
     self.logger_handlers = []
     self.orig_streams = {}
     self.temp_stream = StringIONotifying(self.log_updated)
     self.screen_size = (140, 35)
     self.disabled = False
     self.console = None
     self.executor_widgets = []
     self.screen = DummyScreen(self.screen_size[0], self.screen_size[1])
Beispiel #4
0
class ConsoleStatusReporter(Reporter, AggregatorListener, Singletone):
    """
    Class to show process status on the console
    :type logger_handlers: list[StreamHandler]
    """

    # NOTE: maybe should use separate thread for screen re-painting
    def __init__(self):
        super(ConsoleStatusReporter, self).__init__()
        self._last_datapoint = None
        self.__streams_redirected = False
        self.logger_handlers = []
        self.orig_streams = {}
        self.temp_stream = StringIONotifying(self.log_updated)
        self.screen_size = (140, 35)
        self.disabled = False
        self.console = None
        self.executor_widgets = []
        self.screen = DummyScreen(self.screen_size[0], self.screen_size[1])

    def _get_screen(self):
        screen_type = self._get_screen_type()
        if screen_type == "console":
            return ConsoleScreen()
        elif screen_type == "gui":
            return GUIScreen()
        else:
            cols = self.settings.get('dummy-cols', self.screen_size[0])
            rows = self.settings.get('dummy-rows', self.screen_size[1])
            return DummyScreen(cols, rows)

    def _get_screen_type(self):
        screen_type = self.settings.get("screen", "console")

        if screen_type not in ("console", "gui", "dummy"):
            self.log.info("Invalid screen type %r, trying 'console'",
                          screen_type)
            screen_type = "console"

        if not sys.stdout.isatty():
            self.log.debug("Not in terminal, using dummy screen")
            screen_type = "dummy"

        if screen_type == "console":
            if ConsoleScreen is DummyScreen or is_windows():
                self.log.debug("Can't use 'console' screen, trying 'gui'")
                screen_type = "gui"

        if screen_type == "gui" and GUIScreen is DummyScreen:
            self.log.debug("Can't use 'gui' screen, trying 'dummy'")
            screen_type = "dummy"

        return screen_type

    def prepare(self):
        """
        Prepare console screen objects, logger, ask for widgets
        """
        super(ConsoleStatusReporter, self).prepare()
        if isinstance(self.engine.aggregator, ResultsProvider):
            self.engine.aggregator.add_listener(self)

        disable = self.settings.get('disable', 'auto')
        explicit_disable = isinstance(disable, (bool, int)) and disable
        auto_disable = str(
            disable).lower() == 'auto' and not sys.stdout.isatty()
        if explicit_disable or auto_disable or self.engine.is_functional_mode(
        ):
            self.disabled = True
            return

        self.screen = self._get_screen()

        widgets = []
        modules = [self.engine.provisioning
                   ]  # must create new list to not alter existing
        modules += self.engine.reporters
        modules += self.engine.services
        if isinstance(self.engine.provisioning, Local):
            modules += self.engine.provisioning.executors
        for module in modules:
            if isinstance(module, WidgetProvider):
                widget = module.get_widget()
                widgets.append(widget)
                if isinstance(widget, ExecutorWidget):
                    self.executor_widgets.append(widget)

        self.console = TaurusConsole(widgets)
        self.screen.register_palette(self.console.palette)

    def check(self):
        """
        Repaint the screen
        """
        if self.disabled:
            if self._last_datapoint:
                self.__print_one_line_stats()
                self._last_datapoint = None
            return False

        self.__start_screen()
        for widget in self.executor_widgets:
            widget.update()
        self.__update_screen()
        return False

    def __print_one_line_stats(self):
        cur = self._last_datapoint[DataPoint.CURRENT]['']
        line = "Current: %s vu\t%s succ\t%s fail\t%.3f avg rt"
        stats = (cur[KPISet.CONCURRENCY], cur[KPISet.SUCCESSES],
                 cur[KPISet.FAILURES], cur[KPISet.AVG_RESP_TIME])
        cumul = self._last_datapoint[DataPoint.CUMULATIVE]['']
        line += "\t/\t"  # separator
        line += "Cumulative: %.3f avg rt, %d%% failures"
        stats += (cumul[KPISet.AVG_RESP_TIME],
                  100 * (cumul[KPISet.FAILURES] / cumul[KPISet.SAMPLE_COUNT]))
        self.log.info(line % stats)

    def __start_screen(self):
        """
        Start GUIScreen on windows or urwid.curses_display on *nix
        :return:
        """
        if not self.screen.started:
            self.__redirect_streams()
            self.screen.start()
            self.log.info("Waiting for finish...")

    def __update_screen(self):
        """
        update screen size, update log entries
        call screen.__repaint()
        :return:
        """
        if self.screen.started:
            self.console.tick()

            self.screen_size = self.screen.get_cols_rows()

            self.console.update_log(self.temp_stream)
            try:
                self.__repaint()
            except KeyboardInterrupt:
                raise
            except BaseException as exc:
                self.log.error("Console screen failure: %s", exc)
                self.log.debug("%s", traceback.format_exc())
                self.shutdown()

    def aggregated_second(self, data):
        """
        Consume aggregate data and feed it to console screen

        :type data: bzt.modules.aggregator.DataPoint
        :return:
        """
        self._last_datapoint = data

        if self.disabled:
            return

        try:
            self.console.add_data(data)
        except BaseException as exc:
            self.log.warning("Failed to add datapoint to display: %s", exc)
            self.log.debug("%s", traceback.format_exc())

    def startup(self):
        super(ConsoleStatusReporter, self).startup()
        self.log.info("Waiting for results...")

    def shutdown(self):
        """
        Stop showing the screen
        """
        super(ConsoleStatusReporter, self).shutdown()
        if self.disabled:
            return

        self.screen.stop()
        self.__dump_saved_log()

    def post_process(self):
        super(ConsoleStatusReporter, self).post_process()
        self.__dump_saved_log()

    def __detect_console_logger(self):
        logger = self.log
        while logger:
            for handler in logger.handlers[:]:
                if isinstance(handler, StreamHandler):
                    if handler.stream in (sys.stdout, sys.stderr):
                        self.logger_handlers.append(handler)

            if logger.root == logger:
                break
            else:
                logger = logger.root

    def __redirect_streams(self):
        if self.__streams_redirected:
            return

        if isinstance(self.screen, DummyScreen):
            return

        if sys.stdout.isatty():
            if not is_windows():
                self.__detect_console_logger()

        if self.orig_streams:
            raise TaurusInternalException(
                "Console: original streams already set")
        elif self.logger_handlers and not self.orig_streams:
            self.log.debug("Overriding logging streams")
            for handler in self.logger_handlers:
                self.orig_streams[handler] = handler.stream
                handler.stream = self.temp_stream
            self.log.debug("Redirected logging streams, %s/%s",
                           self.logger_handlers, self.orig_streams)
            self.__streams_redirected = True
        else:
            self.log.info("Did not mute console logging")

    def __dump_saved_log(self):
        """
        Dump data from background logging buffer to orig_stream
        """
        if self.logger_handlers and self.orig_streams:
            # dump what we have in our background logging stream
            self.log.debug("Restoring logging streams, %s/%s",
                           self.logger_handlers, self.orig_streams)
            for handler in self.logger_handlers[:]:
                handler.stream = self.orig_streams[handler]
                self.temp_stream.seek(0)
                handler.stream.write(self.temp_stream.getvalue())
                self.logger_handlers.remove(handler)
                self.orig_streams.pop(handler)
            self.temp_stream.truncate(0)
        else:
            self.log.debug("No logger_handler or orig_stream was detected")

    def __repaint(self):
        if self.screen.started:
            canvas = self.console.render(self.screen_size, focus=False)
            self.screen.draw_screen(self.screen_size, canvas)

    def log_updated(self):
        """
        Notification for log changes, to repaint log widget
        """
        self.console.update_log(self.temp_stream)
        # we need to repaint, otherwise graceful shutdown messages not visible
        self.__repaint()
Beispiel #5
0
class ConsoleStatusReporter(Reporter, AggregatorListener, Singletone):
    """
    Class to show process status on the console
    :type logger_handlers: list[StreamHandler]
    """

    # NOTE: maybe should use separate thread for screen re-painting
    def __init__(self):
        super(ConsoleStatusReporter, self).__init__()
        self._last_datapoint = None
        self.__streams_redirected = False
        self.logger_handlers = []
        self.orig_streams = {}
        self.temp_stream = StringIONotifying(self.log_updated)
        self.screen_size = (140, 35)
        self.disabled = False
        self.console = None
        self.executor_widgets = []
        self.screen = DummyScreen(self.screen_size[0], self.screen_size[1])

    def _get_screen(self):
        screen_type = self._get_screen_type()
        if screen_type == "console":
            return ConsoleScreen()
        elif screen_type == "gui":
            return GUIScreen()
        else:
            cols = self.settings.get('dummy-cols', self.screen_size[0])
            rows = self.settings.get('dummy-rows', self.screen_size[1])
            return DummyScreen(cols, rows)

    def _get_screen_type(self):
        screen_type = self.settings.get("screen", "console")

        if screen_type not in ("console", "gui", "dummy"):
            self.log.info("Invalid screen type %r, trying 'console'", screen_type)
            screen_type = "console"

        if not sys.stdout.isatty():
            self.log.debug("Not in terminal, using dummy screen")
            screen_type = "dummy"

        if screen_type == "console":
            if ConsoleScreen is DummyScreen or is_windows():
                self.log.debug("Can't use 'console' screen, trying 'gui'")
                screen_type = "gui"

        if screen_type == "gui" and GUIScreen is DummyScreen:
            self.log.debug("Can't use 'gui' screen, trying 'dummy'")
            screen_type = "dummy"

        return screen_type

    def prepare(self):
        """
        Prepare console screen objects, logger, ask for widgets
        """
        super(ConsoleStatusReporter, self).prepare()
        if isinstance(self.engine.aggregator, ResultsProvider):
            self.engine.aggregator.add_listener(self)

        disable = self.settings.get('disable', 'auto')
        explicit_disable = isinstance(disable, (bool, int)) and disable
        auto_disable = str(disable).lower() == 'auto' and not sys.stdout.isatty()
        if explicit_disable or auto_disable or self.engine.is_functional_mode():
            self.disabled = True
            return

        self.screen = self._get_screen()

        widgets = []
        modules = [self.engine.provisioning]  # must create new list to not alter existing
        modules += self.engine.reporters
        modules += self.engine.services
        if isinstance(self.engine.provisioning, Local):
            modules += self.engine.provisioning.executors
        for module in modules:
            if isinstance(module, WidgetProvider):
                widget = module.get_widget()
                widgets.append(widget)
                if isinstance(widget, ExecutorWidget):
                    self.executor_widgets.append(widget)

        self.console = TaurusConsole(widgets)
        self.screen.register_palette(self.console.palette)

    def check(self):
        """
        Repaint the screen
        """
        if self.disabled:
            if self._last_datapoint:
                self.__print_one_line_stats()
                self._last_datapoint = None
            return False

        self.__start_screen()
        for widget in self.executor_widgets:
            widget.update()
        self.__update_screen()
        return False

    def __print_one_line_stats(self):
        cur = self._last_datapoint[DataPoint.CURRENT]['']
        line = "Current: %s vu\t%s succ\t%s fail\t%.3f avg rt"
        stats = (cur[KPISet.CONCURRENCY], cur[KPISet.SUCCESSES], cur[KPISet.FAILURES],
                 cur[KPISet.AVG_RESP_TIME])
        cumul = self._last_datapoint[DataPoint.CUMULATIVE]['']
        line += "\t/\t"  # separator
        line += "Cumulative: %.3f avg rt, %d%% failures"
        stats += (cumul[KPISet.AVG_RESP_TIME], 100 * (cumul[KPISet.FAILURES] / cumul[KPISet.SAMPLE_COUNT]))
        self.log.info(line % stats)

    def __start_screen(self):
        """
        Start GUIScreen on windows or urwid.curses_display on *nix
        :return:
        """
        if not self.screen.started:
            self.__redirect_streams()
            self.screen.start()
            self.log.info("Waiting for finish...")

    def __update_screen(self):
        """
        update screen size, update log entries
        call screen.__repaint()
        :return:
        """
        if self.screen.started:
            self.console.tick()

            self.screen_size = self.screen.get_cols_rows()

            self.console.update_log(self.temp_stream)
            try:
                self.__repaint()
            except KeyboardInterrupt:
                raise
            except BaseException as exc:
                self.log.error("Console screen failure: %s", exc)
                self.log.debug("%s", traceback.format_exc())
                self.shutdown()

    def aggregated_second(self, data):
        """
        Consume aggregate data and feed it to console screen

        :type data: bzt.modules.aggregator.DataPoint
        :return:
        """
        self._last_datapoint = data

        if self.disabled:
            return

        try:
            self.console.add_data(data)
        except BaseException as exc:
            self.log.warning("Failed to add datapoint to display: %s", exc)
            self.log.debug("%s", traceback.format_exc())

    def startup(self):
        super(ConsoleStatusReporter, self).startup()
        self.log.info("Waiting for results...")

    def shutdown(self):
        """
        Stop showing the screen
        """
        super(ConsoleStatusReporter, self).shutdown()
        if self.disabled:
            return

        self.screen.stop()
        self.__dump_saved_log()

    def post_process(self):
        super(ConsoleStatusReporter, self).post_process()
        self.__dump_saved_log()

    def __detect_console_logger(self):
        logger = self.log
        while logger:
            for handler in logger.handlers[:]:
                if isinstance(handler, StreamHandler):
                    if handler.stream in (sys.stdout, sys.stderr):
                        self.logger_handlers.append(handler)

            if logger.root == logger:
                break
            else:
                logger = logger.root

    def __redirect_streams(self):
        if self.__streams_redirected:
            return

        if isinstance(self.screen, DummyScreen):
            return

        if sys.stdout.isatty():
            if not is_windows():
                self.__detect_console_logger()

        if self.orig_streams:
            raise TaurusInternalException("Console: original streams already set")
        elif self.logger_handlers and not self.orig_streams:
            self.log.debug("Overriding logging streams")
            for handler in self.logger_handlers:
                self.orig_streams[handler] = handler.stream
                handler.stream = self.temp_stream
            self.log.debug("Redirected logging streams, %s/%s", self.logger_handlers, self.orig_streams)
            self.__streams_redirected = True
        else:
            self.log.info("Did not mute console logging")

    def __dump_saved_log(self):
        """
        Dump data from background logging buffer to orig_stream
        """
        if self.logger_handlers and self.orig_streams:
            # dump what we have in our background logging stream
            self.log.debug("Restoring logging streams, %s/%s", self.logger_handlers, self.orig_streams)
            for handler in self.logger_handlers[:]:
                handler.stream = self.orig_streams[handler]
                self.temp_stream.seek(0)
                handler.stream.write(self.temp_stream.getvalue())
                self.logger_handlers.remove(handler)
                self.orig_streams.pop(handler)
            self.temp_stream.truncate(0)
        else:
            self.log.debug("No logger_handler or orig_stream was detected")

    def __repaint(self):
        if self.screen.started:
            canvas = self.console.render(self.screen_size, focus=False)
            self.screen.draw_screen(self.screen_size, canvas)

    def log_updated(self):
        """
        Notification for log changes, to repaint log widget
        """
        self.console.update_log(self.temp_stream)
        # we need to repaint, otherwise graceful shutdown messages not visible
        self.__repaint()
Beispiel #6
0
class ConsoleStatusReporter(Reporter, AggregatorListener):
    """
    Class to show process status on the console
    :type logger_handlers: list[logging.StreamHandler]
    """

    # NOTE: maybe should use separate thread for screen re-painting
    def __init__(self):
        super(ConsoleStatusReporter, self).__init__()
        self.__report_wait_logged = False
        self.__streams_redirected = False
        self.logger_handlers = []
        self.orig_streams = {}
        self.temp_stream = StringIONotifying(self.log_updated)
        self.screen_size = (140, 35)
        self.data_started = False
        self.disabled = False
        self.console = None
        self.screen = DummyScreen(self.screen_size[0], self.screen_size[1])

    def _get_screen(self):
        screen_type = self._get_screen_type()
        if screen_type == "console":
            return ConsoleScreen()
        elif screen_type == "gui":
            return GUIScreen()
        else:
            cols = self.settings.get('dummy-cols', self.screen_size[0])
            rows = self.settings.get('dummy-rows', self.screen_size[1])
            return DummyScreen(cols, rows)

    def _get_screen_type(self):
        screen_type = self.settings.get("screen", "console")

        if screen_type not in ("console", "gui", "dummy"):
            self.log.info("Invalid screen type %r, trying 'console'", screen_type)
            screen_type = "console"

        if not sys.stdout.isatty():
            self.log.debug("Not in terminal, using dummy screen")
            screen_type = "dummy"

        if screen_type == "console":
            if ConsoleScreen is None or is_windows():
                self.log.debug("Can't use console' screen, trying 'gui'")
                screen_type = "gui"

        if screen_type == "gui" and GUIScreen is None:
            self.log.debug("Can't use 'gui' screen, trying 'dummy'")
            screen_type = "dummy"

        return screen_type

    def prepare(self):
        """
        Prepare console screen objects, logger, ask for widgets
        """
        super(ConsoleStatusReporter, self).prepare()
        self.disabled = self.settings.get("disable", False)
        if self.disabled:
            return

        self.screen = self._get_screen()

        widgets = []
        modules = [self.engine.provisioning]  # must create new list to not alter existing
        modules += self.engine.reporters
        modules += self.engine.services
        if isinstance(self.engine.provisioning, Local):
            modules += self.engine.provisioning.executors
        for module in modules:
            if isinstance(module, WidgetProvider):
                widgets.append(module.get_widget())

        self.console = TaurusConsole(widgets)
        self.screen.register_palette(self.console.palette)
        if isinstance(self.engine.aggregator, ResultsProvider):
            self.engine.aggregator.add_listener(self)

    def check(self):
        """
        Repaint the screen
        """
        if self.disabled:
            self.log.info("Test is running...")
            return False

        if not self.data_started:
            if not self.__report_wait_logged:
                self.log.info("Waiting to get first results...")
                self.__report_wait_logged = True
            return False

        self.__start_screen()
        self.__update_screen()
        return False

    def __start_screen(self):
        """
        Start GUIScreen on windows or urwid.curses_display on *nix
        :return:
        """
        if self.data_started and not self.screen.started:
            self.__redirect_streams()
            self.screen.start()
            self.log.info("Waiting for finish...")

    def __update_screen(self):
        """
        update screen size, update log entries
        call screen.__repaint()
        :return:
        """
        if self.screen.started:
            self.console.tick()

            self.screen_size = self.screen.get_cols_rows()

            self.console.update_log(self.temp_stream)
            try:
                self.__repaint()
            except KeyboardInterrupt:
                raise
            except BaseException:
                self.log.error("Console screen failure: %s", traceback.format_exc())
                self.shutdown()

    def aggregated_second(self, data):
        """
        Consume aggregate data and feed it to console screen

        :type data: bzt.modules.aggregator.DataPoint
        :return:
        """
        if self.disabled:
            return

        try:
            self.console.add_data(data)
        except BaseException:
            self.log.warn("Failed to add datapoint to display: %s", traceback.format_exc())

        self.data_started = True

    def shutdown(self):
        """
        Stop showing the screen
        """
        super(ConsoleStatusReporter, self).shutdown()
        if self.disabled:
            return

        self.screen.stop()
        self.__dump_saved_log()

    def post_process(self):
        super(ConsoleStatusReporter, self).post_process()
        self.__dump_saved_log()

    def __detect_console_logger(self):
        logger = self.log
        while logger:
            for handler in logger.handlers[:]:
                if isinstance(handler, StreamHandler):
                    if handler.stream in (sys.stdout, sys.stderr):
                        self.logger_handlers.append(handler)

            if logger.root == logger:
                break
            else:
                logger = logger.root

    def __redirect_streams(self):
        if self.__streams_redirected:
            return

        if sys.stdout.isatty():
            if not is_windows():
                self.__detect_console_logger()

        if self.data_started and not self.screen.started:
            if self.orig_streams:
                raise RuntimeError("Orig streams already set")
            elif self.logger_handlers and not self.orig_streams:
                self.log.debug("Overriding logging streams")
                for handler in self.logger_handlers:
                    self.orig_streams[handler] = handler.stream
                    handler.stream = self.temp_stream
                self.log.debug("Redirected logging streams, %s/%s", self.logger_handlers, self.orig_streams)
                self.__streams_redirected = True
            else:
                self.log.info("Did not mute console logging")

    def __dump_saved_log(self):
        """
        Dump data from background logging buffer to orig_stream
        """
        if self.logger_handlers and self.orig_streams:
            # dump what we have in our background logging stream
            self.log.debug("Restoring logging streams, %s/%s", self.logger_handlers, self.orig_streams)
            for handler in self.logger_handlers[:]:
                handler.stream = self.orig_streams[handler]
                self.temp_stream.seek(0)
                handler.stream.write(self.temp_stream.getvalue())
                self.logger_handlers.remove(handler)
                self.orig_streams.pop(handler)
            self.temp_stream.truncate(0)
        else:
            self.log.debug("No logger_handler or orig_stream was detected")

    def __repaint(self):
        if self.screen.started:
            canvas = self.console.render(self.screen_size, focus=False)
            self.screen.draw_screen(self.screen_size, canvas)

    def log_updated(self):
        """
        Notification for log changes, to repaint log widget
        """
        self.console.update_log(self.temp_stream)
        # we need to repaint, otherwise graceful shutdown messages not visible
        self.__repaint()