mirror of
https://github.com/apache/activemq.git
synced 2025-02-17 07:24:51 +00:00
git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@565392 13f79535-47bb-0310-9956-ffa450edef68
337 lines
14 KiB
Python
Executable File
337 lines
14 KiB
Python
Executable File
"""
|
|
Module Connection
|
|
"""
|
|
import itertools
|
|
|
|
class Connection(object):
|
|
"""
|
|
This class represents an ActiveMQ Connection.
|
|
It also stores a collection of the connections
|
|
that have been read in the log files.
|
|
|
|
A Connection's id is the ActiveMQConnection's id. Since this is usually a long
|
|
alphanumerical string, it is called 'longId'.
|
|
Each new Connection gets also assigned an integer 'shortId' automatically.
|
|
The function of this 'shortId' is to make understanding of displayed data easier.
|
|
|
|
A Connection has 2 LogFile members, who represent:
|
|
-the log file of the JVM that initiates a connection.
|
|
-the log file of the JVM that receives a connection request.
|
|
|
|
The purpose of every Connection is to store the following data:
|
|
|
|
-messages sent through this connection, as a dictionary where the
|
|
key is a tuple (message, direction) and the value is
|
|
a list of timestamps. If the message was sent only one time (normal case),
|
|
the timestamp list will have 1 item only.
|
|
|
|
-messages received through this connection, as a dictionary
|
|
analogous to the previous one.
|
|
|
|
-messages sent but not received through this connection, as a list of
|
|
tuples (storedMessage, ntimes, timestamps).
|
|
'storedMessage' is a (message, direction) tuple
|
|
ntimes, an integer, is the number of times a message was sent but not received
|
|
timestamps is a list of timestamps of when the message was sent or received.
|
|
For a message to be in this list, ntimes must be >= 1.
|
|
|
|
-messages received but not sent through this connection.
|
|
Analog to previous point.
|
|
|
|
-messages sent more than 2 more times through this connection, as a list of
|
|
tuples (storedMessage, ntimes, timestamps).
|
|
'storedMessage' is a (message, direction) tuple
|
|
ntimes, an integer, is the number of times a message was sent.
|
|
timestamps is a list of timestamps of when the message was sent.
|
|
For a message to be in this list, ntimes must be >= 2.
|
|
|
|
-messages received more than 2 more times through this connection.
|
|
Identical structure to the previous point.
|
|
|
|
The 'direction' value is either True or False.
|
|
True represents that the message was sent from the JVM writing to the
|
|
'from' file, to the JVM writing to the 'to' file.
|
|
False represents the opposite.
|
|
"""
|
|
|
|
#dictionary whose keys are connection ids, and whose values
|
|
#are Connection objects
|
|
connections = {}
|
|
nConnections = 0
|
|
connectionIdList = []
|
|
|
|
def __init__(self, longId, fromFile = None, toFile = None):
|
|
"""
|
|
Constructs a Connection object.
|
|
longId : string
|
|
fromFile: LogFile object
|
|
to: LogFile object
|
|
The ActiveMQConnection's id has to be provided.
|
|
Optionally, 2 LogFile objects can be provided.
|
|
The 'from' file is the log file of the JVM that initiates a connection.
|
|
The 'to' file is the log file of the JVM that receives a connection request.
|
|
|
|
A new connection gets automatically a new 'shortId', which is an integer.
|
|
The longId gets also stored in a list of longIds.
|
|
|
|
Returns a Connection object.
|
|
"""
|
|
|
|
self.longId = longId
|
|
self.fromFile = fromFile
|
|
self.toFile = toFile
|
|
|
|
self.shortId = Connection.nConnections
|
|
Connection.connectionIdList.append(longId)
|
|
Connection.nConnections += 1
|
|
|
|
self.producers = set()
|
|
self.consumers = set()
|
|
|
|
self.sent = {}
|
|
self.received = {}
|
|
|
|
self.duplicateSent = None
|
|
self.duplicateReceived = None
|
|
self.sentButNotReceived = None
|
|
self.receivedButNotSent = None
|
|
|
|
self.calculated = False
|
|
|
|
@classmethod
|
|
def clearData(cls):
|
|
"""
|
|
Deletes all information read about connections.
|
|
|
|
Returns nothing.
|
|
"""
|
|
|
|
cls.connections.clear()
|
|
cls.nConnections = 0
|
|
del cls.connectionIdList[:]
|
|
|
|
@classmethod
|
|
def getConnectionByLongId(cls, longId):
|
|
"""
|
|
Retrieves the connection whose id is 'longId'.
|
|
If there is no connection with this id, a new
|
|
one is created with this id.
|
|
|
|
Returns a Connection object.
|
|
"""
|
|
|
|
if longId not in cls.connections:
|
|
cls.connections[longId] = Connection(longId)
|
|
|
|
return cls.connections[longId]
|
|
|
|
@classmethod
|
|
def getConnectionByShortId(cls, shortId):
|
|
"""
|
|
Retrieves the connection whose shortId is 'shortId'.
|
|
If there is no connection with this id,
|
|
an IndexError exception will be thrown.
|
|
|
|
Returns a Connection object.
|
|
Throws an IndexError if the short id does not exist.
|
|
"""
|
|
|
|
return cls.connections[cls.connectionIdList[shortId]]
|
|
|
|
@classmethod
|
|
def shortIdToLongId(cls, shortId):
|
|
"""
|
|
Transforms a connection's short id to a long id.
|
|
Returns the long id.
|
|
Throws an IndexError if the short id does not exist.
|
|
"""
|
|
return cls.connectionIdList[shortId]
|
|
|
|
@classmethod
|
|
def longIdToShortId(cls, longId):
|
|
"""
|
|
Transforms a connection's long id to a short id.
|
|
Returns the short id.
|
|
Throws an KeyError if the short id does not exist.
|
|
"""
|
|
try:
|
|
return cls.connections[longId].shortId
|
|
except KeyError:
|
|
print longId
|
|
print cls.connections
|
|
raise
|
|
|
|
@classmethod
|
|
def setFrom(cls, longId, fromFile):
|
|
"""
|
|
Sets the 'from' LogFile object for the connection whose id is 'longId'.
|
|
The 'from' file is the log file of the JVM that initiates a connection.
|
|
If there is not yet a connection whose id is 'longId', a new one is
|
|
created with this longId and this 'from' file.
|
|
|
|
Returns nothing.
|
|
"""
|
|
|
|
if longId not in cls.connections:
|
|
cls.connections[longId] = Connection(longId, fromFile = fromFile)
|
|
else:
|
|
cls.connections[longId].fromFile = fromFile
|
|
|
|
@classmethod
|
|
def setTo(cls, longId, toFile):
|
|
"""
|
|
Sets the 'to' LogFile object for the connection whose id is 'longId'.
|
|
The 'to' file is the log file of the JVM that receives a connection request.
|
|
If there is not yet a connection whose id is 'longId', a new one is
|
|
created with this longId and this 'to' file.
|
|
|
|
Returns nothing.
|
|
"""
|
|
|
|
if longId not in cls.connections:
|
|
cls.connections[longId] = Connection(longId, toFile = toFile)
|
|
else:
|
|
cls.connections[longId].toFile = toFile
|
|
|
|
|
|
|
|
@classmethod
|
|
def exists(cls, longId):
|
|
"""
|
|
Returns if there is a connection whose id is 'longId'
|
|
"""
|
|
|
|
return longId in cls.connections
|
|
|
|
|
|
|
|
def addProducer(self, producer):
|
|
"""
|
|
Adds a producer to the set of this connection's producers.
|
|
Returns nothing.
|
|
"""
|
|
self.producers.add(producer)
|
|
|
|
def addConsumer(self, consumer):
|
|
"""
|
|
Adds a consumer to the set of this connection's consumers.
|
|
Returns nothing.
|
|
"""
|
|
self.consumers.add(consumer)
|
|
|
|
def addSentMessage(self, message, direction, timestamp):
|
|
"""
|
|
Adds a message to the set of messages sent through this connection.
|
|
message: a Message object
|
|
direction: True if this message was sent from self.fromFile to self.to
|
|
False if this message was sent from self.toFile to self.fromFile
|
|
timestamp: a string with the time this message was sent
|
|
|
|
If the message has already been sent in this direction, it gets added to the
|
|
collection of duplicate sent messages.
|
|
|
|
Returns nothing.
|
|
"""
|
|
|
|
storedMessage = (message, direction)
|
|
|
|
if storedMessage in self.sent:
|
|
self.sent[storedMessage].append(timestamp)
|
|
else:
|
|
self.sent[storedMessage] = [timestamp]
|
|
|
|
def addReceivedMessage(self, message, direction, timestamp):
|
|
"""
|
|
Adds a message to the set of messages received through this connection.
|
|
message: a message object
|
|
direction: True if this message was sent from self.fromFile to self.to
|
|
False if this message was sent from self.toFile to self.fromFile
|
|
timestamp: a string with the time this message was sent
|
|
|
|
If the message has already been received in this direction, it gets added to the
|
|
collection of duplicate received messages.
|
|
|
|
Returns nothing.
|
|
"""
|
|
|
|
storedMessage = (message, direction)
|
|
|
|
if storedMessage in self.received:
|
|
self.received[storedMessage].append(timestamp)
|
|
else:
|
|
self.received[storedMessage] = [timestamp]
|
|
|
|
def getErrors(self):
|
|
"""
|
|
Processes the data previously gathered to find incorrect situations.
|
|
|
|
Returns a 4-tuple with:
|
|
-collection of sent but not received messages, through this Connection.
|
|
This collection is a list of (storedMessage, ntimes, timestamps) tuples where:
|
|
*'storedMessage' is a (message, direction) tuple.
|
|
*'ntimes' is an integer, representing how many times the message was sent but not received.
|
|
*'timestamps' is a list of strings with the timestamps when this message was sent / received.
|
|
|
|
-collection of received but not sent messages, through this Connection.
|
|
This collection is a list of (storedMessage, ntimes, timestamps) tuples where:
|
|
*'storedMessage' is a (message, direction) tuple.
|
|
*'ntimes' is an integer, representing how many times the message was received but not sent.
|
|
*'timestamps' is a list of strings with the timestamps when this message was sent / received.
|
|
|
|
-collection of duplicate sent messages, through this Connection.
|
|
This collection is a list of (message, timestamps) tuples where:
|
|
*'storedMessage' is a (shortId, commandId, direction) tuple.
|
|
*'ntimes' is an integer, representing how many times the message sent.
|
|
*'timestamps' is a list of strings with the timestamps when this message was sent.
|
|
|
|
-collection of duplicate received messages, through this Connection.
|
|
This collection is a list of (message, timestamps) tuples where:
|
|
*'storedMessage' is a (message, direction) tuple.
|
|
*'ntimes' is an integer, representing how many times the message received.
|
|
*'timestamps' is a list of strings with the timestamps when this message was received.
|
|
|
|
The data is only calculated once, and then successive calls of this method return always
|
|
the same erros unles self.calculated is set to False.
|
|
"""
|
|
|
|
if not self.calculated:
|
|
self.sentButNotReceived = []
|
|
for message, timestamps in self.sent.iteritems():
|
|
if message not in self.received:
|
|
self.sentButNotReceived.append((message, len(timestamps), timestamps))
|
|
else:
|
|
difference = len(timestamps) - len(self.received[message])
|
|
if difference > 0:
|
|
self.sentButNotReceived.append((message, difference,
|
|
itertools.chain(timestamps, self.received[message])))
|
|
|
|
self.receivedButNotSent = []
|
|
for message, timestamps in self.received.iteritems():
|
|
if message not in self.sent:
|
|
self.receivedButNotSent.append((message, len(timestamps), timestamps))
|
|
else:
|
|
difference = len(timestamps) - len(self.sent[message])
|
|
if difference > 0:
|
|
self.receivedButNotSent.append((message, difference,
|
|
itertools.chain(timestamps, self.sent[message])))
|
|
|
|
self.duplicateSent = [(message, len(timestamps), timestamps)
|
|
for message, timestamps in self.sent.iteritems() if len(timestamps) > 1]
|
|
self.duplicateReceived = [(message, len(timestamps), timestamps)
|
|
for message, timestamps in self.received.iteritems() if len(timestamps) > 1]
|
|
|
|
self.sentButNotReceived.sort(key = lambda message: (message[0][0].producer.shortId, message[0][0].prodSeqId))
|
|
self.receivedButNotSent.sort(key = lambda message: (message[0][0].producer.shortId, message[0][0].prodSeqId))
|
|
self.duplicateSent.sort(key = lambda message: (message[0][0].producer.shortId, message[0][0].prodSeqId))
|
|
self.duplicateReceived.sort(key = lambda message: (message[0][0].producer.shortId, message[0][0].prodSeqId))
|
|
|
|
self.calculated = True
|
|
|
|
return self.sentButNotReceived, self.receivedButNotSent, self.duplicateSent, self.duplicateReceived
|
|
|
|
def __str__(self):
|
|
"""
|
|
Represents this Connection object as a string.
|
|
"""
|
|
|
|
return ''.join([self.longId, ' from:', str(self.fromFile), ' to:', str(self.toFile)]) |