Example #1
0
    def report(self, reporter, tag, ts, delta,
               level, message,
               alevel, attachments):
        """
        Report messages to the console or logfile in a line-by-line
        format prefixing each line.
        """
        # FIXME: rework the streaming object so it can multiplex the
        # output to two file descriptors *and* decide based on
        # verbosity; this way we do not have to walk the attachmen
        # tree and format twice if the log file is enabled.

        # the prefix to each line is stored in thraed-local-storage
        # (with commonl.tls_prefix_c), where it is picked up by the
        # stream buffer object commonl.io_tls_prefix_lines_c. This,
        # before printing, adds the prefix to each line.
        _prefix = "%s%d/%s\t%s [+%.1fs]: " % (
            tag, level, tcfl.msgid_c.ident(),
            reporter._report_prefix, delta
        )
        with commonl.tls_prefix_c(self.tls, _prefix):
            console_p, logfile_p = self._shall_do(level)
            message += "\n"
            if console_p:
                self.consolef.write(message)
            if self.logf and logfile_p:
                self.logf.write(message)

        if attachments != None:
            assert isinstance(attachments, dict)
            console_p, logfile_p = self._shall_do(alevel)
            if console_p or logfile_p:
                _aprefix = "%s%d/%s\t%s [+%.1fs]:    " % (
                    tag, alevel, tcfl.msgid_c.ident(),
                    reporter._report_prefix, delta
                )
                with commonl.tls_prefix_c(self.tls, _aprefix):
                    if console_p:
                        commonl.data_dump_recursive_tls(attachments, self.tls,
                                                        of = self.consolef)
                    if self.logf and logfile_p:
                        commonl.data_dump_recursive_tls(attachments, self.tls,
                                                        of = self.logf)

        self.consolef.flush()
        if self.logf:
            self.logf.flush()
Example #2
0
    def report(self, testcase, target, tag, ts, delta, level, message, alevel,
               attachments):
        """
        Writes data to per-testcase/target temporary logfiles to
        render upon completion all the configured templates.

        We don't even check the levels, we log everything here by
        INFO <= 4.

        We report to the file ``TAG LEVEL CODE MESSAGE`` which we'll
        parse later to generate the report. When a *COMPLETION*
        message is reported, we assume the testcase is completed and
        call _mkreport() to render the templates.
        """
        if testcase == tc.tc_global:  # ignore the global reporter
            return
        # FIXME: config
        if tag == "INFO" and level > 4:  # ignore way chatty stuff
            return

        # Who's is this coming from?
        if target:
            tgname = "@" + target.fullid
        else:
            tgname = "@local"

        # Note we open the file for every thing we report -- we can be
        # running *A LOT* of stuff in parallel and run out of file
        # descriptors. get stream LRU caches them -- pass arguments
        # like that (instead of passing the testcase) so the LRU cache
        # decorator in _get_fd() can use it to hash.
        # NOTE WE ALWAYS save relative to the testcase's tmpdir, not
        # the reporter.tmpdir, which might be different (if the
        # reporter is a target)
        of = self._get_fd(testcase.ticket, testcase.tmpdir)
        # Remove the ticket from the ident string, as it will be
        # the same for all and makes no sense to have it.
        ident = testcase.ident()
        if ident == "":
            # If empty, give it a to snip token that we'll replace
            # later in mkreport
            ident = "<snip>"

        # The of file descriptor uses a buffer implementation that
        # takes the prefix from a thread-local-storage for every line
        # it writes, so just use that to flush the message and the
        # attachments.
        _prefix = u"%s %d %s %s\t " % (tag, level, ident, tgname)
        with commonl.tls_prefix_c(self.tls, _prefix):
            if not message.endswith('\n'):
                message += "\n"
            # @of writes _prefix for us, because we set it with
            # commonl.tls_prefix_c and @of is a
            # commonl.io_tls_prefix_lines_c(), which prefixes _prefix
            # on each line.
            # the timestamp is a horrible hack which we have to fix
            # properly by propagating it as a field in the temporary
            # log so later the templates can decide how to render it

            # if timezone is not set we will use local, if it is, we
            # change it to the one set by the user.
            # we need to localize the timezone before changing it, we can get
            # it in UTC straight from the timestamp, so no need to be guessing
            # the timezone of the machine.
            if self.timezone:
                try:
                    d = datetime.datetime.fromtimestamp(
                        ts, pytz.timezone(self.timezone))
                except pytz.exceptions.UnknownTimeZoneError:
                    logging.warning(
                        f"bad timezone '{self.timezone}' set for reporting."
                        f" REPORT_TZ: {os.environ.get('REPORT_TZ', 'n/a/')},"
                        f" TZ: {os.environ.get('TZ', 'n/a')}; defaulting to local"
                    )
                    d = datetime.datetime.fromtimestamp(ts)
            else:
                d = datetime.datetime.fromtimestamp(ts)
            # e.g. 22-02-28.12:56:00
            d = d.strftime('%y-%m-%d.%H:%M:%S')
            of.write(f"[{d} +{delta:.1f}s] " + message)

        if attachments != None:
            # FIXME: \x01\x01 hack to denote an attachment, will
            # replace in _log_iterator() because the intermediate
            # format we have splits spaces--real fix will be to
            # convert that format to something more flexible
            _prefix = u"%s %d %s %s\t \x01\x01" % (tag, level, ident, tgname)
            with commonl.tls_prefix_c(self.tls, _prefix):
                assert isinstance(attachments, dict)
                commonl.data_dump_recursive_tls(attachments, self.tls, of=of)
        of.flush()
        # This is an indication that the testcase is done and we
        # can generate final reports
        if message.startswith("COMPLETION "):
            of.flush()
            self._mkreport(tag, testcase.ticket, testcase, message)
            # Wipe the file, it might have errors--it might be not
            # a file, so wipe hard
            #commonl.rm_f(self.fs[reporter.ticket])
            del self.fs[testcase.ticket]
            # can't remove from the _get_fd() cache, but it will be
            # removed once it's unused
            of.close()
            del of
Example #3
0
    def report(self, reporter, tag, ts, delta,
               level, message,
               alevel, attachments):
        """
        Writes data to per-testcase/target temporary logfiles to
        render upon completion all the configured templates.

        We don't even check the levels, we log everything here by
        INFO <= 4.

        We report to the file ``TAG LEVEL CODE MESSAGE`` which we'll
        parse later to generate the report. When a *COMPLETION*
        message is reported, we assume the testcase is completed and
        call _mkreport() to render the templates.
        """
        if reporter == tc.tc_global:		# ignore the global reporter
            return
        # FIXME: config
        if tag == "INFO" and level > 4:	# ignore way chatty stuff
            return

        # Note we open the file for every thing we report -- we can be
        # running *A LOT* of stuff in parallel and run out of file
        # descriptors. get stream LRU caches them -- pass arguments
        # like that (instead of passing the testcase) so the LRU cache
        # decorator in _get_fd() can use it to hash.
        of = self._get_fd(reporter.ticket, reporter.tmpdir)

        # Extract the target name where this message came from (if the
        # reporter is a target, otherwise we consider it a local message)
        if isinstance(reporter, tc.target_c):
            tgname = "@" + reporter.fullid + reporter.bsp_suffix()
        else:
            tgname = "@local"

        # Remove the ticket from the ident string, as it will be
        # the same for all and makes no sense to have it.
        ident = self.ident_simplify(tcfl.msgid_c.ident(),
                                    reporter.kws.get('runid', ''),
                                    reporter.kws.get('tc_hash', ""))
        if ident == "":
            # If empty, give it a to snip token that we'll replace
            # later in mkreport
            ident = "<snip>"

        # The of file descriptor uses a buffer implementation that
        # takes the prefix from a thread-local-storage for every line
        # it writes, so just use that to flush the message and the
        # attachments.
        _prefix = u"%s %d %s %s\t " % (tag, level, ident, tgname)
        with commonl.tls_prefix_c(self.tls, _prefix):
            if not message.endswith('\n'):
                message += "\n"
            of.write(message)
            if attachments != None:
                assert isinstance(attachments, dict)
                commonl.data_dump_recursive_tls(attachments, self.tls,
                                                of = of)
            of.flush()
        # This is an indication that the testcase is done and we
        # can generate final reports
        if message.startswith("COMPLETION "):
            of.flush()
            self._mkreport(tag, reporter.ticket, reporter, message)
            # Wipe the file, it might have errors--it might be not
            # a file, so wipe hard
            #commonl.rm_f(self.fs[reporter.ticket])
            del self.fs[reporter.ticket]
            # can't remove from the _get_fd() cache, but it will be
            # removed once it's unused
            of.close()
            del of
Example #4
0
    def report(self, testcase, target, tag, ts, delta, level, message, alevel,
               attachments):
        """
        Report messages to the console or logfile in a line-by-line
        format prefixing each line.
        """
        # FIXME: rework the streaming object so it can multiplex the
        # output to two file descriptors *and* decide based on
        # verbosity; this way we do not have to walk the attachmen
        # tree and format twice if the log file is enabled.

        # the prefix to each line is stored in thraed-local-storage
        # (with commonl.tls_prefix_c), where it is picked up by the
        # stream buffer object commonl.io_tls_prefix_lines_c. This,
        # before printing, adds the prefix to each line.

        if target:
            fullid = "|" + target.fullid
        else:
            fullid = ""

        tag_to_color = {
            "PASS": ("green", ),
            "ERRR": ("magenta", ),
            "FAIL": ("red", ),
            "BLCK": ("yellow", ),
            "SKIP": ('cyan', ),  # no orange available...
            'DATA': ("blue", ),
        }
        console_p, logfile_p = self._shall_do(testcase, level, message)
        if console_p:
            # if this is a terminal, colorize the TAG in the main
            # message so we can easily locate issues; note we don't
            # colorize the tag for attachments, just for the main
            # message.
            # We don't colorize INFO nor DATA
            # we don't do windows yet
            if sys.platform != "win32" and self.consolef.isatty(
            ) and tag in tag_to_color:
                args = tag_to_color[tag]
                _taglevel = termcolor.colored(f"{tag}{level}",
                                              *args,
                                              attrs=['bold'])
                _prefix = _taglevel + \
                    f"/{termcolor.colored(testcase.runid_hashid, attrs = [ 'bold' ])}{testcase.ident()}" \
                    f" {termcolor.colored(testcase._report_prefix, *args)}{fullid}" \
                    f" [+{delta:0.1f}s]: "
            else:
                _prefix = \
                    f"{tag}{level}/{testcase.runid_hashid}{testcase.ident()}" \
                    f" {testcase._report_prefix}{fullid} [+{delta:0.1f}s]: "
            with commonl.tls_prefix_c(self.tls, _prefix):
                message += "\n"
                self.consolef.write(message)
        if logfile_p:
            _prefix = \
                f"{tag}{level}/{testcase.runid_hashid}{testcase.ident()}" \
                f" {testcase._report_prefix}{fullid} [+{delta:0.1f}s]: "
            with commonl.tls_prefix_c(self.tls, _prefix):
                message += "\n"
                if self.logf and logfile_p:
                    self.logf.write(message)

        if attachments != None:
            assert isinstance(attachments, dict)
            console_p, logfile_p = self._shall_do(testcase, alevel)
            if console_p or logfile_p:
                # note the extra two spaces at the end, those are so
                # the attachments are printed indented; it's much
                # easier to read
                _aprefix = \
                    f"{tag}{alevel}/{testcase.runid_hashid}{testcase.ident()}"  \
                    f" {testcase._report_prefix}{fullid} [+{delta:0.1f}s]:   "
                with commonl.tls_prefix_c(self.tls, _aprefix):
                    if console_p:
                        commonl.data_dump_recursive_tls(attachments,
                                                        self.tls,
                                                        of=self.consolef)
                    if self.logf and logfile_p:
                        commonl.data_dump_recursive_tls(attachments,
                                                        self.tls,
                                                        of=self.logf)

        self.consolef.flush()
        if self.logf:
            self.logf.flush()