Exemplo n.º 1
0
 def discover_connection_facts(self, comn):
     '''
     Discover all the connections in this router-instance log
     For each connection:
      * determine connection direction
      * discover name of peer container
      * generate html to use to display the peer nickname
      * count log lines
      * count transfer bytes
     :param comn:
     :return:
     '''
     for item in self.lines:
         if item.data.is_scraper:
             # scraper lines are pass-through
             continue
         conn_num = int(item.data.conn_num)
         id = item.data.conn_id  # full name A0_3
         if conn_num not in self.conn_list:
             cdir = ""
             if item.data.direction != "":
                 cdir = item.data.direction
             else:
                 if "Connecting" in item.data.web_show_str:
                     cdir = text.direction_out()
                 elif "Accepting" in item.data.web_show_str:
                     cdir = text.direction_in()
             self.conn_list.append(conn_num)
             self.conn_to_frame_map[id] = []
             self.conn_dir[id] = cdir
             self.conn_log_lines[id] = 0  # line counter
             self.conn_xfer_bytes[id] = 0  # byte counter
             self.conn_open_time[id] = item
         self.conn_to_frame_map[id].append(item)
         # inbound open handling
         if item.data.name == "open" and item.data.direction == text.direction_in(
         ):
             if item.data.conn_id in self.conn_peer:
                 sys.exit(
                     'ERROR: file: %s connection %s has multiple connection peers'
                     % (self.fn, id))
             self.conn_peer[id] = item.data.conn_peer
             self.conn_peer_display[
                 id] = comn.shorteners.short_peer_names.translate(
                     item.data.conn_peer, True)
         # close monitor
         if item.data.name == "close":
             self.conn_close_time[id] = item
         # connection log-line count
         self.conn_log_lines[id] += 1
         # transfer byte count
         if item.data.name == "transfer":
             self.conn_xfer_bytes[id] += int(item.data.transfer_size)
     self.conn_list = sorted(self.conn_list)
     self.details = amqp_detail.AllDetails(self, comn)
Exemplo n.º 2
0
 def discover_connection_facts(self, comn):
     '''
     Discover all the connections in this router-instance log
     For each connection:
      * determine connection direction
      * discover name of peer container
      * generate html to use to display the peer nickname
      * count log lines
      * count transfer bytes
     :param comn:
     :return:
     '''
     for item in self.lines:
         conn_num = int(item.data.conn_num)
         id = item.data.conn_id           # full name A0_3
         if conn_num not in self.conn_list:
             cdir = ""
             if item.data.direction != "":
                 cdir = item.data.direction
             else:
                 if "Connecting" in item.data.web_show_str:
                     cdir = text.direction_out()
                 elif "Accepting" in item.data.web_show_str:
                     cdir = text.direction_in()
             self.conn_list.append(conn_num)
             self.conn_to_frame_map[id] = []
             self.conn_dir[id] = cdir
             self.conn_log_lines[id] = 0   # line counter
             self.conn_xfer_bytes[id] = 0  # byte counter
             self.conn_open_time[id] = item
         self.conn_to_frame_map[id].append(item)
         # inbound open handling
         if item.data.name == "open" and item.data.direction == text.direction_in():
             if item.data.conn_id in self.conn_peer:
                 sys.exit('ERROR: file: %s connection %s has multiple connection peers' % (
                 self.fn, id))
             self.conn_peer[id] = item.data.conn_peer
             self.conn_peer_display[id] = comn.shorteners.short_peer_names.translate(
                 item.data.conn_peer, True)
         # close monitor
         if item.data.name == "close":
             self.conn_close_time[id] = item
         # connection log-line count
         self.conn_log_lines[id] += 1
         # transfer byte count
         if item.data.name == "transfer":
             self.conn_xfer_bytes[id] += int(item.data.transfer_size)
     self.conn_list = sorted(self.conn_list)
     self.details = amqp_detail.AllDetails(self, comn)
Exemplo n.º 3
0
 def direction_is_in(self):
     return self.direction == text.direction_in()
Exemplo n.º 4
0
    def extract_facts(self):
        perf = self.data.described_type.dtype_number
        res = self.data
        resdict = self.data.described_type.dict

        # the performatives
        # Note: res.channel is already populated
        if perf == 0x10:
            # Performative: open [0] always channel 0
            res.name = "open"
            res.channel = "0"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)
            if res.direction == text.direction_in():
                res.conn_peer = self.resdict_value(resdict, "container-id",
                                                   "unknown")
                res.web_show_str += (" (peer: %s)" % res.conn_peer)

        elif perf == 0x11:
            # Performative: begin [channel,remoteChannel]
            # TODO: This has a bug where the local and remote channel numbers are confused.
            #       Usually they are the same. See if anyone notices!
            # res.channel
            res.name = "begin"
            res.remote = self.resdict_value(resdict, "remote-channel", "None)")
            res.channel_remote = "[%s,%s]" % (res.channel, res.remote)
            res.web_show_str = "<strong>%s</strong> %s" % (res.name,
                                                           res.channel_remote)

        elif perf == 0x12:
            # Performative:  attach [channel,handle] role name (source: src, target: tgt)
            res.name = "attach"
            res.handle = resdict["handle"]
            res.role = "receiver" if resdict["role"] == "true" else "sender"
            res.is_receiver = res.role == "receiver"
            name = self.resdict_value(resdict, "name", "None")
            res.link_short_name_popup = self.shorteners.short_link_names.translate(
                name, True, customer=self)
            res.link_short_name = self.shorteners.short_link_names.translate(
                name, False)
            tmpsrc = self.resdict_value(resdict, "source", None)
            tmptgt = self.resdict_value(resdict, "target", None)
            res.snd_settle_mode = self.sender_settle_mode_of(
                resdict["snd-settle-mode"]
            ) if "snd-settle-mode" in resdict else "mixed"
            res.rcv_settle_mode = self.receiver_settle_mode_of(
                resdict["rcv-settle-mode"]
            ) if "rcv-settle-mode" in resdict else "first"
            caps = ""
            if tmpsrc is not None:
                res.source = self.resdict_value(tmpsrc.dict, "address", "none")
                caps = self.resdict_value(tmpsrc.dict, "capabilities", "")
            else:
                res.source = "none"
            if tmptgt is not None:
                res.target = self.resdict_value(tmptgt.dict, "address", "none")
                if caps == "":
                    caps = self.resdict_value(tmptgt.dict, "capabilities", "")
            else:
                res.target = "none"
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)

            if 'qd.router-data' in caps:
                res.link_class = 'router-data'
            elif 'qd.router' in caps:
                res.link_class = 'router'
            """
            TODO:
            res.source = short_endp_names.translate(res.source)
            res.target = short_endp_names.translate(res.target)
            res.snd_settle_mode = extract_name(tmpssm)
            res.rcv_settle_mode = extract_name(tmprsm)
            """
            res.web_show_str = (
                "<strong>%s</strong> %s %s %s (source: %s, target: %s, class: %s)"
                % (res.name, colorize_bg(
                    res.channel_handle), res.role, res.link_short_name_popup,
                   res.source, res.target, res.link_class))

        elif perf == 0x13:
            # Performative: flow [channel,handle]
            res.name = "flow"
            res.handle = resdict["handle"]
            res.flow_deliverycnt = self.resdict_value(resdict,
                                                      "delivery-count", "0")
            res.flow_linkcredit = self.resdict_value(resdict, "link-credit",
                                                     "0")
            res.flow_drain = resdict.get("drain", "") == "true"
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.flow_cnt_credit = "(%s,%s)" % (res.flow_deliverycnt,
                                               res.flow_linkcredit)
            res.web_show_str = "<strong>%s</strong> %s (%s,%s) %s" % (
                res.name, colorize_bg(res.channel_handle),
                res.flow_deliverycnt, res.flow_linkcredit,
                self.highlighted("drain", res.flow_drain,
                                 common.color_of("drain")))

        elif perf == 0x14:
            # Performative: transfer [channel,handle] (id)
            res.name = "transfer"
            res.transfer = True
            res.handle = resdict["handle"]
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.delivery_id = self.resdict_value(resdict, "delivery-id",
                                                 "none")
            res.delivery_tag = self.resdict_value(resdict, "delivery-tag",
                                                  "none")
            res.settled = self.resdict_value(resdict, "settled", "false")
            res.transfer_settled = resdict.get("settled", "") == "true"
            res.transfer_more = resdict.get("more", "") == "true"
            res.transfer_resume = resdict.get("resume", "") == "true"
            res.transfer_aborted = resdict.get("aborted", "") == "true"
            self.transfer_short_name = self.shorteners.short_data_names.translate(
                res.transfer_bare, customer=self)
            showdat = "<a href=\"#%s_dump\">%s</a>" % (
                self.transfer_short_name, self.transfer_short_name)
            res.web_show_str = "<strong>%s</strong>  %s (%s) %s %s %s %s %s - %s bytes" % (
                res.name, colorize_bg(res.channel_handle), res.delivery_id,
                self.highlighted("settled", res.transfer_settled,
                                 common.color_of("presettled")),
                self.highlighted("more", res.transfer_more,
                                 common.color_of("more")),
                self.highlighted("resume", res.transfer_resume,
                                 common.color_of("aborted")),
                self.highlighted(
                    "aborted", res.transfer_aborted,
                    common.color_of("aborted")), showdat, res.transfer_size)

        elif perf == 0x15:
            # Performative: disposition [channel] (role first-last)
            res.name = "disposition"
            res.role = "receiver" if resdict["role"] == "true" else "sender"
            res.is_receiver = res.role == "receiver"
            res.first = self.resdict_value(resdict, "first", "0")
            res.last = self.resdict_value(resdict, "last", res.first)
            res.settled = self.resdict_value(resdict, "settled", "false")
            state = resdict.get("state")
            if state is not None:
                res.disposition_state = state.dtype_name
            ###    colorize_dispositions_not_accepted(proto, res, global_vars, count_anomalies)
            res.web_show_str = (
                "<strong>%s</strong>  [%s] (%s %s-%s)" %
                (res.name, res.channel, res.role, res.first, res.last))

        elif perf == 0x16:
            # Performative: detach [channel, handle]
            res.name = "detach"
            res.handle = resdict["handle"]
            ### TODO: colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.web_show_str = "<strong>%s</strong> %s" % (
                res.name, colorize_bg(res.channel_handle))

        elif perf == 0x17:
            # Performative: end [channel]
            res.name = "end"
            ### TODO: colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x18:
            # Performative: close [0] always channel 0
            res.channel = "0"
            res.name = "close"
            ### colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x1d:
            # transport:definitions error
            res.name = "error"
            descr = self.resdict_value(resdict, "description", "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (
                res.name, res.channel, descr)

        elif perf == 0x23:
            # messaging:delivery-state received
            res.name = "received"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x24:
            # messaging:delivery-state accepted
            res.name = "accepted"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x25:
            # messaging:delivery-state rejected
            res.name = "rejected"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x26:
            # messaging:delivery-state released
            res.name = "released"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x27:
            # messaging:delivery-state modified
            res.name = "modified"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x28:
            # messaging:addressing source
            res.name = "source"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x29:
            # messaging:addressing target
            res.name = "target"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x2b:
            # messaging:addressing delete-on-close
            res.name = "delete-on-close"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x2c:
            # messaging:addressing delete-on-no-links
            res.name = "delete-on-no-links"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x2d:
            # messaging:addressing delete-on-no-messages
            res.name = "delete-on-no-messages"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x2e:
            # messaging:addressing delete-on-no-links-or-messages
            res.name = "delete-on-no-links-or-messages"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x30:
            # transactions:coordination coordinator
            res.name = "coordinator"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x31:
            # transactions:coordination declare
            res.name = "declare"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x32:
            # transactions:coordination discharge
            res.name = "discharge"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x33:
            # transactions:coordination declared
            res.name = "declared"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x34:
            # transactions:coordination transactional-state
            res.name = "transactional-state"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x40:
            # security:sasl sasl-mechanisms
            res.name = "sasl-mechanisms"
            mechs = self.resdict_value(resdict, "sasl-server-mechanisms",
                                       "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (
                res.name, res.channel, mechs)

        elif perf == 0x41:
            # security:sasl sasl-init
            res.name = "sasl-init"
            mech = self.resdict_value(resdict, "mechanism", "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (
                res.name, res.channel, mech)

        elif perf == 0x42:
            # security:sasl sasl-challenge
            res.name = "sasl-challenge"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x43:
            # security:sasl sasl-response
            res.name = "sasl-response"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x44:
            # security:sasl sasl-outcome
            res.name = "sasl-outcome"
            code = self.resdict_value(resdict, "code", "none")
            res.web_show_str = "<strong>%s</strong> [%s] code=%s" % (
                res.name, res.channel, code)

        elif perf == 0x70:
            # messaging:message-format header
            res.name = "header"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x71:
            # messaging:message-format delivery-annotations
            res.name = "delivery-annotations"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x72:
            # messaging:message-format message-annotations
            res.name = "message-annotations"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x73:
            # messaging:message-format properties
            res.name = "properties"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x74:
            # messaging:message-format application-properties
            res.name = "application-properties"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x75:
            # messaging:message-format data
            res.name = "data"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x76:
            # messaging:message-format amqp-sequence
            res.name = "amqp-sequence"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x77:
            # messaging:message-format amqp-value
            res.name = "amqp-value"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        elif perf == 0x78:
            # messaging:message-format footer
            res.name = "footer"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name,
                                                             res.channel)

        else:
            res.web_show_str = "HELP I'M A ROCK - Unknown performative: %s" % perf

        if "error" in resdict:
            res.amqp_error = True
            dct = resdict["error"].dict
            condi = dct["condition"]
            descr = dct["description"] if "description" in dct else ""
            res.web_show_str += (
                " <span style=\"background-color:%s\">error</span> "
                "%s %s" % (common.color_of("errors"), condi, descr))
Exemplo n.º 5
0
    def evaluate_credit(self):
        for conn in self.rtr.conn_list:
            id = self.rtr.conn_id(conn)
            conn_detail = self.rtr.details.conn_details[id]
            for sess in conn_detail.session_list:
                for link in sess.link_list:
                    # ignore links without starting attach
                    if link.frame_list[0].data.name != "attach":
                        link.counts.credit_not_evaluated += 1
                        sess.counts.credit_not_evaluated += 1
                        conn_detail.counts.credit_not_evaluated += 1
                        break
                    # process flaggage
                    look_for_sender_delivery_id = True
                    dir_of_xfer = ''
                    dir_of_flow = ''
                    current_delivery = 0 # next transfer expected id
                    delivery_limit = 0 # first unreachable delivery id from flow
                    n_attaches = 0
                    tod_of_second_attach = None
                    multiframe_in_progress = False
                    init_stall = True
                    credit_stall = False
                    tod_of_no_credit = None
                    tod_of_shutdown = None
                    # record info about initial attach
                    is_rcvr = link.frame_list[0].data.is_receiver
                    o_dir = link.frame_list[0].data.direction
                    # derive info about where to look for credit and transfer id
                    #  role dir  transfers flow w/credit case
                    #  ---- ---- --------- ------------- ----
                    #  rcvr  <-   ->        <-            A
                    #  rcvr  ->   <-        ->            B
                    #  sndr  <-   <-        ->            B
                    #  sndr  ->   ->        <-            A
                    #
                    if (((is_rcvr) and (o_dir == text.direction_in())) or
                        ((not is_rcvr) and (o_dir == text.direction_out()))):
                        # case A
                        dir_of_xfer = text.direction_out()
                        dir_of_flow = text.direction_in()
                    else:
                        # case B
                        dir_of_xfer = text.direction_in()
                        dir_of_flow = text.direction_out()

                    for plf in link.frame_list:
                        # initial credit delay starts at reception of second attach
                        if n_attaches < 2:
                            if plf.data.name == "attach":
                                n_attaches += 1
                                if n_attaches == 2:
                                    tod_of_second_attach = plf.datetime
                        if look_for_sender_delivery_id:
                            if plf.data.name == "attach" and not plf.data.is_receiver:
                                current_delivery = int(plf.data.described_type.dict.get("initial-delivery_count", "0"))
                                delivery_limit = current_delivery
                                look_for_sender_delivery_id = False

                        if plf.data.name == "flow":
                            if plf.data.direction == dir_of_flow:
                                # a flow in the normal direction updates the delivery limit
                                dc = plf.data.described_type.dict.get("delivery-count", "0")
                                lc = plf.data.described_type.dict.get("link-credit", "0")
                                delivery_limit = int(dc) + int(lc)  # TODO: wrap at 32-bits
                                if n_attaches < 2:
                                    # a working flow before sender attach - cancel initial stall
                                    init_stall = False
                                if init_stall:
                                    init_stall = False
                                    dur = plf.datetime - tod_of_second_attach
                                    link.counts.initial_no_credit_duration = dur
                                    sess.counts.initial_no_credit_duration += dur
                                    conn_detail.counts.initial_no_credit_duration += dur
                                if credit_stall and delivery_limit > current_delivery: # TODO: wrap
                                    credit_stall = False
                                    plf.data.web_show_str += " <span style=\"background-color:%s\">credit restored</span>" % common.color_of("no_credit")
                                    dur = plf.datetime - tod_of_no_credit
                                    link.counts.no_credit_duration += dur
                                    sess.counts.no_credit_duration += dur
                                    conn_detail.counts.no_credit_duration += dur
                            else:
                                # flow in the opposite direction updates the senders current delivery
                                # normally used to consume credit in response to a drain from receiver
                                current_delivery = int(plf.data.described_type.dict.get("initial-delivery_count", "0"))

                        elif plf.data.transfer:
                            if plf.data.direction == dir_of_xfer:
                                if not plf.data.transfer_more:
                                    # consider the transfer to have arrived when last transfer seen
                                    current_delivery += 1 # TODO: wrap at 32-bits
                                    if current_delivery == delivery_limit:
                                        link.counts.no_credit += 1
                                        sess.counts.no_credit += 1
                                        conn_detail.counts.no_credit += 1
                                        plf.data.transfer_exhausted_credit = True
                                        credit_stall = True
                                        plf.data.web_show_str += " <span style=\"background-color:%s\">no more credit</span>" % common.color_of("no_credit")
                                        tod_of_no_credit = plf.datetime
                                    else:
                                        pass # still have credit
                                    multiframe_in_progress = False
                                else:
                                    # transfers with 'more' set don't consume credit
                                    multiframe_in_progress = True
                            else:
                                pass   # transfer in wrong direction??

                        elif plf.data.name == "detach":
                            tod_of_shutdown = plf.datetime
                            break

                    # clean up lingering credit stall
                    if init_stall or credit_stall:
                        if tod_of_shutdown is None:
                            # find first end or close and call that shutdown time
                            for plf in sess.session_frame_list:
                                if plf.data.name == "end":
                                    tod_of_shutdown = plf.datetime
                                    break
                            if tod_of_shutdown is None:
                                for plf in conn_detail.unaccounted_frame_list:
                                    if plf.data.name == "close":
                                        tod_of_shutdown = plf.datetime
                                        break
                                if tod_of_shutdown is None:
                                    # Hmmm, no shutdown. Use last link frame
                                    tod_of_shutdown = link.frame_list[-1].datetime
                        if tod_of_second_attach is None:
                            # Hmmm, no second attach. Use first link frame time
                            tod_of_second_attach = link.frame_list[0].datetime
                        if init_stall:
                            dur = tod_of_shutdown - tod_of_second_attach
                            link.counts.initial_no_credit_duration = dur
                            sess.counts.initial_no_credit_duration += dur
                            conn_detail.counts.initial_no_credit_duration += dur
                        if credit_stall: # TODO: wrap
                            dur = tod_of_shutdown - tod_of_no_credit
                            link.counts.no_credit_duration += dur
                            sess.counts.no_credit_duration += dur
                            conn_detail.counts.no_credit_duration += dur

                    # record multiframe transfer that didn't complete
                    if multiframe_in_progress:
                        link.counts.incomplete += 1
                        sess.counts.incomplete += 1
                        conn_detail.counts.incomplete += 1
Exemplo n.º 6
0
 def direction_is_in(self):
     return self.direction == text.direction_in()
Exemplo n.º 7
0
    def extract_facts(self):
        perf = self.data.described_type.dtype_number
        res = self.data
        resdict = self.data.described_type.dict

        # the performatives
        # Note: res.channel is already populated
        if perf == 0x10:
            # Performative: open [0] always channel 0
            res.name = "open"
            res.channel = "0"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)
            if res.direction == text.direction_in():
                res.conn_peer = self.resdict_value(resdict, "container-id", "unknown")
                res.web_show_str += (" (peer: %s)" % res.conn_peer)

        elif perf == 0x11:
            # Performative: begin [channel,remoteChannel]
            # TODO: This has a bug where the local and remote channel numbers are confused.
            #       Usually they are the same. See if anyone notices!
            # res.channel
            res.name = "begin"
            res.remote = self.resdict_value(resdict, "remote-channel", "None)")
            res.channel_remote = "[%s,%s]" % (res.channel, res.remote)
            res.web_show_str = "<strong>%s</strong> %s" % (res.name, res.channel_remote)

        elif perf == 0x12:
            # Performative:  attach [channel,handle] role name (source: src, target: tgt)
            res.name = "attach"
            res.handle = resdict["handle"]
            res.role = "receiver" if resdict["role"] == "true" else "sender"
            res.is_receiver = res.role == "receiver"
            name = self.resdict_value(resdict, "name", "None")
            res.link_short_name_popup = self.shorteners.short_link_names.translate(name, True)
            res.link_short_name = self.shorteners.short_link_names.translate(name, False)
            tmpsrc = self.resdict_value(resdict, "source", None)
            tmptgt = self.resdict_value(resdict, "target", None)
            res.snd_settle_mode = self.sender_settle_mode_of(
                resdict["snd-settle-mode"]) if "snd-settle-mode" in resdict else "mixed"
            res.rcv_settle_mode = self.receiver_settle_mode_of(
                resdict["rcv-settle-mode"]) if "rcv-settle-mode" in resdict else "first"
            caps = ""
            if tmpsrc is not None:
                res.source = self.resdict_value(tmpsrc.dict, "address", "none")
                caps = self.resdict_value(tmpsrc.dict, "capabilities", "")
            else:
                res.source = "none"
            if tmptgt is not None:
                res.target = self.resdict_value(tmptgt.dict, "address", "none")
                if caps == "":
                    caps = self.resdict_value(tmptgt.dict, "capabilities", "")
            else:
                res.target = "none"
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)

            if 'qd.router-data' in caps:
                res.link_class = 'router-data'
            elif 'qd.router' in caps:
                res.link_class = 'router'
            """
            TODO:
            res.source = short_endp_names.translate(res.source)
            res.target = short_endp_names.translate(res.target)
            res.snd_settle_mode = extract_name(tmpssm)
            res.rcv_settle_mode = extract_name(tmprsm)
            """
            res.web_show_str = ("<strong>%s</strong> %s %s %s (source: %s, target: %s, class: %s)" %
                                (res.name, colorize_bg(res.channel_handle), res.role, res.link_short_name_popup,
                                 res.source, res.target, res.link_class))

        elif perf == 0x13:
            # Performative: flow [channel,handle]
            res.name = "flow"
            res.handle = resdict["handle"]
            res.flow_deliverycnt = self.resdict_value(resdict, "delivery-count", "0")
            res.flow_linkcredit = self.resdict_value(resdict, "link-credit", "0")
            res.flow_drain = resdict.get("drain", "") == "true"
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.flow_cnt_credit = "(%s,%s)" % (res.flow_deliverycnt, res.flow_linkcredit)
            res.web_show_str = "<strong>%s</strong> %s (%s,%s) %s" % (
                res.name, colorize_bg(res.channel_handle), res.flow_deliverycnt, res.flow_linkcredit,
                self.highlighted("drain", res.flow_drain, "yellow"))

        elif perf == 0x14:
            # Performative: transfer [channel,handle] (id)
            res.name = "transfer"
            res.handle = resdict["handle"]
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.delivery_id = self.resdict_value(resdict, "delivery-id", "none")
            res.delivery_tag = self.resdict_value(resdict, "delivery-tag", "none")
            res.settled = self.resdict_value(resdict, "settled", "false")
            res.transfer_settled = resdict.get("settled", "") == "true"
            res.transfer_more = resdict.get("more", "") == "true"
            res.transfer_resume = resdict.get("resume", "") == "true"
            res.transfer_aborted = resdict.get("aborted", "") == "true"
            self.transfer_short_name = self.shorteners.short_data_names.translate(res.transfer_bare)
            showdat = "<a href=\"#%s\">%s</a>" % (self.transfer_short_name, self.transfer_short_name)
            res.web_show_str = "<strong>%s</strong>  %s (%s) %s %s %s %s %s - %s bytes" % (
                res.name, colorize_bg(res.channel_handle), res.delivery_id,
                self.highlighted("settled", res.transfer_settled, "green"),
                self.highlighted("more", res.transfer_more, "purple"),
                self.highlighted("resume", res.transfer_resume, "orange"),
                self.highlighted("aborted", res.transfer_aborted, "yellow"),
                showdat, res.transfer_size)

        elif perf == 0x15:
            # Performative: disposition [channel] (role first-last)
            res.name = "disposition"
            res.role = "receiver" if resdict["role"] == "true" else "sender"
            res.is_receiver = res.role == "receiver"
            res.first = self.resdict_value(resdict, "first", "0")
            res.last = self.resdict_value(resdict, "last", res.first)
            res.settled = self.resdict_value(resdict, "settled", "false")
            state = resdict.get("state")
            if state is not None:
                res.disposition_state = state.dtype_name
            ###    colorize_dispositions_not_accepted(proto, res, global_vars, count_anomalies)
            res.web_show_str = ("<strong>%s</strong>  [%s] (%s %s-%s)" %
                                (res.name, res.channel, res.role, res.first, res.last))

        elif perf == 0x16:
            # Performative: detach [channel, handle]
            res.name = "detach"
            res.handle = resdict["handle"]
            ### TODO: colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.channel_handle = "[%s,%s]" % (res.channel, res.handle)
            res.web_show_str = "<strong>%s</strong> %s" % (res.name, colorize_bg(res.channel_handle))

        elif perf == 0x17:
            # Performative: end [channel]
            res.name = "end"
            ### TODO: colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x18:
            # Performative: close [0] always channel 0
            res.channel = "0"
            res.name = "close"
            ### colorize_performative_error(proto, res, global_vars, count_anomalies)
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x1d:
            # transport:definitions error
            res.name = "error"
            descr = self.resdict_value(resdict, "description", "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (res.name, res.channel, descr)

        elif perf == 0x23:
            # messaging:delivery-state received
            res.name = "received"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x24:
            # messaging:delivery-state accepted
            res.name = "accepted"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x25:
            # messaging:delivery-state rejected
            res.name = "rejected"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x26:
            # messaging:delivery-state released
            res.name = "released"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x27:
            # messaging:delivery-state modified
            res.name = "modified"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x28:
            # messaging:addressing source
            res.name = "source"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x29:
            # messaging:addressing target
            res.name = "target"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x2b:
            # messaging:addressing delete-on-close
            res.name = "delete-on-close"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x2c:
            # messaging:addressing delete-on-no-links
            res.name = "delete-on-no-links"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x2d:
            # messaging:addressing delete-on-no-messages
            res.name = "delete-on-no-messages"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x2e:
            # messaging:addressing delete-on-no-links-or-messages
            res.name = "delete-on-no-links-or-messages"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x30:
            # transactions:coordination coordinator
            res.name = "coordinator"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x31:
            # transactions:coordination declare
            res.name = "declare"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x32:
            # transactions:coordination discharge
            res.name = "discharge"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x33:
            # transactions:coordination declared
            res.name = "declared"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x34:
            # transactions:coordination transactional-state
            res.name = "transactional-state"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x40:
            # security:sasl sasl-mechanisms
            res.name = "sasl-mechanisms"
            mechs = self.resdict_value(resdict, "sasl-server-mechanisms", "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (res.name, res.channel, mechs)

        elif perf == 0x41:
            # security:sasl sasl-init
            res.name = "sasl-init"
            mech = self.resdict_value(resdict, "mechanism", "none")
            res.web_show_str = "<strong>%s</strong> [%s] %s" % (res.name, res.channel, mech)

        elif perf == 0x42:
            # security:sasl sasl-challenge
            res.name = "sasl-challenge"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x43:
            # security:sasl sasl-response
            res.name = "sasl-response"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x44:
            # security:sasl sasl-outcome
            res.name = "sasl-outcome"
            code = self.resdict_value(resdict, "code", "none")
            res.web_show_str = "<strong>%s</strong> [%s] code=%s" % (res.name, res.channel, code)

        elif perf == 0x70:
            # messaging:message-format header
            res.name = "header"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x71:
            # messaging:message-format delivery-annotations
            res.name = "delivery-annotations"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x72:
            # messaging:message-format message-annotations
            res.name = "message-annotations"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x73:
            # messaging:message-format properties
            res.name = "properties"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x74:
            # messaging:message-format application-properties
            res.name = "application-properties"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x75:
            # messaging:message-format data
            res.name = "data"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x76:
            # messaging:message-format amqp-sequence
            res.name = "amqp-sequence"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x77:
            # messaging:message-format amqp-value
            res.name = "amqp-value"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        elif perf == 0x78:
            # messaging:message-format footer
            res.name = "footer"
            res.web_show_str = "<strong>%s</strong> [%s]" % (res.name, res.channel)

        else:
            res.web_show_str = "HELP I'M A ROCK - Unknown performative: %s" % perf

        if "error" in resdict:
            res.amqp_error = True
            res.web_show_str += (" <span style=\"background-color:yellow\">error</span> "
                                 "%s %s" % (resdict["error"].dict["condition"], resdict["error"].dict["description"]))