blob: 9fd38353c941e9c2b18e8a7bba580fe6a2d7d70b [file] [log] [blame]
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# A single router log file may contain data from multiple instances of
# that router booting and running. Thus there may be several different
# connections labeled [0] and these connections may be to different
# routers on each run.
#
# The 'router' class defined here represents a single boot-and-run
# instance from the log file.
#
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
import sys
import traceback
import datetime
import amqp_detail
import common
import text
class RestartRecord():
def __init__(self, _router, _line, _lineno):
self.router = _router
self.line = _line
self.lineno = _lineno
try:
self.datetime = datetime.datetime.strptime(self.line[:26], '%Y-%m-%d %H:%M:%S.%f')
except:
self.datetime = datetime.datetime(1970, 1, 1)
def __repr__(self):
return "%d instance %d start %s #%d" % (self.router.log_index, self.router.instance,
self.datetime, self.lineno)
class Router():
'''A single dispatch boot-and-run instance from a log file'''
def __init__(self, _fn, _log_index, _instance):
self.fn = _fn # log file name
self.log_index = _log_index # 0=A, 1=B, ...
self.instance = _instance # log file instance of router
self.iletter = common.log_letter_of(self.log_index) # A
self.iname = self.iletter + str(self.instance) # A0
# discovered Container Name
self.container_name = None
# discovered Version
self.version = None
# discovered mode
self.mode = None
# restart_rec - when this router was identified in log file
self.restart_rec = None
# lines - the log lines as ParsedLogLine objects
self.lines = []
# conn_list - List of connections discovered in log lines
# Sorted in ascending order and not necessarily in packed sequence.
self.conn_list = []
# conn_log_lines - count of log lines per connection
self.conn_log_lines = {}
# conn_transfer_bytes - count of bytes transfered over this connection
self.conn_xfer_bytes = {}
# connection_to_frame_map
self.conn_to_frame_map = {}
# conn_peer - peer container long name
# key= connection id '1', '2'
# val= original peer container name
self.conn_peer = {}
# conn_peer_display - peer container display name
# key= connection id '1', '2'
# val= display name
# Peer display name shortened with popup if necessary
self.conn_peer_display = {}
# conn_peer_connid - display value for peer's connection id
# key= connection id '1', '2'
# val= peer's connid 'A.0_3', 'D.3_18'
self.conn_peer_connid = {}
# conn_dir - arrow indicating connection origin direction
# key= connection id '1', '2'
# val= '<-' peer created conn, '->' router created conn
self.conn_dir = {}
# router_ls - link state 'ROUTER_LS (info)' lines
self.router_ls = []
# open and close times
self.conn_open_time = {} # first log line with [N] seen
self.conn_close_time = {} # last close log line seen
# details: for each connection, for each session, for each link, whaaa?
self.details = None
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)
def conn_id(self, conn_num):
'''
Given this router's connection number return the global connection id
:param conn_num: connection number
:return: conn_id in the for A0_3
'''
return self.iname + "_" + str(conn_num)
def is_interior(self):
return self.mode == "interior"
def which_router_tod(router_list, at_time):
'''
Find a router in a list based on time of day
:param router_list: a list of Router objects
:param at_time: the datetime record identifying the router
:return: tuple: (a router from the list or None, router index)
'''
if len(router_list) == 0:
return (None, 0)
if len(router_list) == 1:
return (router_list[0], 0)
for i in range(1, len(router_list)):
if at_time < router_list[i].restart_rec.datetime:
return (router_list[i-1], i-1)
return (router_list[-1], len(router_list)-1)
def which_router_id_tod(routers, id, at_time):
'''
Find a router by container_name and time of day
:param routers: a list of router instance lists
:param id: the container name
:param at_time: datetime of interest
:return: the router that had that container name at that time; None if not found
'''
for routerlist in routers:
if routerlist[0].container_name == id:
return which_router_tod(routerlist, at_time)
return (None, 0)
if __name__ == "__main__":
try:
pass
except:
traceback.print_exc(file=sys.stdout)
pass