You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ra...@apache.org on 2007/08/13 18:03:27 UTC

svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/

Author: rajdavies
Date: Mon Aug 13 09:03:25 2007
New Revision: 565392

URL: http://svn.apache.org/viewvc?view=rev&rev=565392
Log:
Added the log analyser tool to svn - for http://issues.apache.org/activemq/browse/AMQ-1361

Added:
    activemq/trunk/log_analyzer_tool/
    activemq/trunk/log_analyzer_tool/Main.py   (with props)
    activemq/trunk/log_analyzer_tool/README.txt   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/
    activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.pyc   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.py   (with props)
    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.pyc   (with props)
    activemq/trunk/log_analyzer_tool/run.bat   (with props)
    activemq/trunk/log_analyzer_tool/run.sh   (with props)
    activemq/trunk/log_analyzer_tool/screenshots/
    activemq/trunk/log_analyzer_tool/screenshots/1.png   (with props)
    activemq/trunk/log_analyzer_tool/screenshots/2.png   (with props)
    activemq/trunk/log_analyzer_tool/screenshots/3.png   (with props)
    activemq/trunk/log_analyzer_tool/screenshots/4.png   (with props)
    activemq/trunk/log_analyzer_tool/screenshots/5.png   (with props)

Added: activemq/trunk/log_analyzer_tool/Main.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/Main.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/Main.py (added)
+++ activemq/trunk/log_analyzer_tool/Main.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,14 @@
+"""
+Module Main
+"""
+from loganalyzergui.Application import Application
+
+def main():
+    """
+    Entrance point for the application
+    """
+    app = Application(0)
+    app.MainLoop()
+    
+if __name__ == '__main__':
+    main()
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/Main.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/README.txt
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/README.txt?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/README.txt (added)
+++ activemq/trunk/log_analyzer_tool/README.txt Mon Aug 13 09:03:25 2007
@@ -0,0 +1,64 @@
+Readme file for the LogAnalyzer application.
+
+1. Requirements:
+-Python 2.5.1 (http://www.python.org/download/releases/2.5.1/ or your favorite package)
+-wxPython 2.8.4 (http://www.wxpython.org/download.php or your favorite package)
+
+2. How to execute:
+Run 'python Main.py'.
+
+3. Some instructions:
+-This tool will analyze ActiveMQ log files that have been produced
+using the 'custom' transport log format. To analyze the files,
+put them in a directory, choose that directory and click 'Parse'.
+Please don't put any other kind of files in the same directory
+(sub-directories won't cause any problem, but the files inside
+them will not be analyzed).
+For example, imagine you have a setup with 4 machines: 1 has producers,
+2 are brokers, and 1 has consumers. As long as you have 1 JVM per machine,
+you should have 4 log files. Call the files p.log, b1.log, b2.log,
+and c.log, for example. Put the 4 files in the same directory,
+choose that directory and click the 'Parse' button.
+
+-The first tab of the tool shows incorrect situations at transport level:
+(i) Messages that were sent through a connection, but were not received
+at the other end.
+(ii) Messages that were received through a connection, but were not sent
+(probably you are missing the log file of the JVM that sent the message).
+(iii) Messages that are sent 2 times through the same connection.
+(iv) Messages that were sent 2 times by the same JVM, but through
+different connections.
+By clicking the 'Show results with short ids' checkbox, you can switch
+between the real connection / producer id used by ActiveMQ,
+or a unique integer assigned by the tool.
+Often it's easier to compare and browse with this integers than with
+the original id's which are often long strings.
+The 'Message id' column shows 2 things: the id of the producer that
+originally issued the message, and the 'Producer Sequence Id' of a message.
+These 2 items identify a message in a unique way.
+
+You can use the checkboxes to filter per type.
+You can also filter by a given connection (but then problems of type (iv)
+will not appear because they 'belong' to more than one connection).
+You can input a 'long id' (the original ActiveMQ id) or a 'short id'
+(a short integer assigned by the tool to each connection).
+
+-The second tab of the tool allows you to get a lot of information
+about a single message. Input the producer id of the original producer
+of the message, and the message's 'Producer Sequence Id'.
+You can choose to use the original ActiveMQ producer id (long id)
+or the short integer assigned to a producer by the tool.
+You can also use the 'Jump to Message Browsing' button of the 1st tab
+to see the information about the problems of a given message
+without having to copy the message id manually.
+In this tab you can also use the 'Show results with short ids' checkbox.
+
+-The third tab gives a summary of the clients (producer and consumers)
+which appear in the log files. Each client is identified by a short id,
+and belongs to a connection (whose 'short id' and 'long id' are shown).
+
+-The fourth tab gives a summary of the connections involved,
+and the clients that belong to them.
+
+-The fifth tab gives a summary of the log files analyzed,
+and the connections in each of the files.
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/README.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/trunk/log_analyzer_tool/README.txt
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,337 @@
+"""
+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)])
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,76 @@
+"""
+Module Consumer
+"""
+
+class Consumer(object):
+    """
+    This class represents an ActiveMQ Consumer.
+    Each consumer is identified by its long id.
+    However each consumer also has a short id (an integer) to identify it more easily.
+    """
+    
+    nConsumers = 0
+    consumerIdList = []
+    consumers = {}
+    
+    def __init__(self, longId):
+        """
+        Constructor
+        """
+        
+        self.longId = longId
+        self.shortId = Consumer.nConsumers
+        
+        self.connectionId, sessionId, value = longId.rsplit(':', 2)
+        self.sessionId = int(sessionId)
+        self.value = int(value)
+        
+        Consumer.consumers[longId] = self
+        Consumer.consumerIdList.append(self.longId)
+        Consumer.nConsumers += 1
+    
+    @classmethod
+    def clearData(cls):
+        """
+        Deletes all information read about Consumers.
+        
+        Returns nothing.
+        """
+        
+        cls.consumers.clear()
+        cls.nConsumers = 0
+        del cls.consumerIdList[:]
+    
+    @classmethod
+    def getConsumerByLongId(cls, longId):
+        """
+        Returns a consumer given its long id.
+        If there is no consumer with this long id yet, it will be created.
+        """
+        
+        if longId not in cls.consumers:
+            cls.consumers[longId] = Consumer(longId)
+
+        return cls.consumers[longId]
+    
+    @classmethod
+    def shortIdToLongId(cls, shortId):
+        """
+        Transforms a consumer's short id to a long id.
+        
+        Returns a long id.
+        Throws an IndexError if the short id does not exist.
+        """
+        
+        return cls.consumerIdList[shortId]
+    
+    @classmethod
+    def longIdToShortId(cls, longId):
+        """
+        Transforms a consumer's long id to a short id.
+        
+        Returns a long id.
+        Throws an KeyError if the long id does not exist.
+        """
+        return cls.consumers[longId].shortId
+    

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,187 @@
+"""
+Module LogFile
+"""
+import os
+
+class LogFile(object):
+    """
+    Class that represents an ActiveMQ log file read by the application.
+    It also stores a list of all the LogFile objects.
+    
+    A LogFile object stores the following information:
+    -A list of 'outgoing' Connection objects that represent the connections
+    created by the JVM that writes this LogFile.
+    -A list of 'incoming' Connection objects that represent the connections
+    requests received by the JVM that writes this LogFile.
+    
+    -A dictionary of messages that were sent in this file.
+    The keys are Message objects and the values
+    are lists of timestamps of when the message was sent.
+    -A list of messages that were received in this file.
+    The keys are Message objects and the values
+    are lists of timestamps of when the message was received.
+    
+    -A list of messages that were sent in this file more than 1 time (duplicates)
+    The list is made of (message, ntimes, timestamps) tuples.
+    -A list of messages that were received in this file more than 1 time (duplicates),
+    analogous to the previous structure.
+    """
+    
+    logfiles = []
+    
+    def __init__(self, path):
+        """
+        Constructs a LogFile object.
+        path: a string with the path to the ActiveMQ log file.
+        """
+        
+        self.__path = os.path.abspath(path)
+        self.file = open(self.__path, 'r')
+        self.outgoing = []
+        self.incoming = []
+        
+        self.sent = {}
+        self.received = {}
+        
+        self.duplicateReceived = None
+        self.duplicateSent = None
+        
+        self.calculated = False
+        
+        LogFile.logfiles.append(self)
+       
+    @classmethod
+    def clearData(cls):
+        """
+        Class method erases all the LogFile objects stored in the LogFile class.
+        Returns nothing.
+        """
+        
+        del cls.logfiles[:]
+    
+    @classmethod
+    def closeFiles(cls):
+        """
+        Class method that closes all the LogFile objects stored in the LogFile class.
+        Returns nothing.
+        """
+        
+        for logFile in cls.logfiles:
+            logFile.file.close()
+
+
+
+    def addOutgoingConnection(self, con):
+        """
+        Adds an 'outgoing' Connection object to this LogFile.
+        Returns nothing.
+        """
+        
+        self.outgoing.append(con)
+
+    def addIncomingConnection(self, con):
+        """
+        Adds an 'incoming' Connection object to this LogFile.
+        Returns nothing.
+        """
+        
+        self.incoming.append(con)
+        
+    def addSentMessage(self, message, timestamp):
+        """
+        Adds a message to the set of messages that were sent thtough this file.
+        If a message gets sent 2 times, it gets added to the set of duplicate sent messages.
+        message: a Message object.
+        timestamp: a string with the time where this message was sent.
+        
+        Returns nothing.
+        """
+        
+        if message in self.sent:
+            self.sent[message].append(timestamp)
+        else:
+            self.sent[message] = [timestamp]
+        
+    def addReceivedMessage(self, message, timestamp):
+        """
+        Adds a message to the set of messages that were received in this file.
+        If a message gets sent 2 times, it gets added to the set of duplicate received messages.
+        message: a Message object.
+        timestamp: a string with the time where this message was sent.
+        
+        Returns nothing.
+        """
+        
+        #message = (shortProdId, prodSeqId, False)
+        if message in self.received:
+            self.received[message].append(timestamp)
+        else:
+            self.received[message] = [timestamp]
+            
+    def getErrors(self):
+        """
+        Returns a 2-tuple with:
+            -a list of (message, ntimes, timestamps) tuples, with the duplicate sent messages
+            that appear in more than one connection in this file.
+            'message' is a Message object.
+            'ntimes' is an integer stating how many times the message was sent ( always >= 2)
+            'timestamps' is a list of timestamps with the instants the message was sent.
+            
+            -a list of (message, ntimes, timestamps) tuples, with the duplicate received messages
+            that appear in more than one connection in this file.
+            Structure analogous to previous one.
+        
+        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:
+            
+            duplicateSentTemp = [(message, len(timestamps), timestamps)
+                                 for message, timestamps in self.sent.iteritems() if len(timestamps) > 1]
+            self.duplicateSent = []
+            
+            for message, _, timestamps in duplicateSentTemp:
+                connections = []
+                for connection, direction in message.sendingConnections:
+                    if direction and connection.fromFile == self       \
+                    or not direction and connection.toFile == self:
+                        connections.append(connection)
+                if len(connections) > 1:
+                    self.duplicateSent.append((message, len(timestamps), timestamps))
+                    
+            duplicateReceivedTemp = [(message, len(timestamps), timestamps)
+                                      for message, timestamps in self.received.iteritems() if len(timestamps) > 1]
+            self.duplicateReceived = []
+            
+            for message, _, timestamps in duplicateReceivedTemp:
+                connections = []
+                for connection, direction in message.receivingConnections:
+                    if direction and connection.toFile == self       \
+                    or not direction and connection.fromFile == self:
+                        connections.append(connection)
+                if len(connections) > 1:
+                    self.duplicateReceived.append((message, len(timestamps), timestamps))
+                    
+            self.duplicateSent.sort(key = lambda message: (message[0].producer.shortId, message[0].prodSeqId))
+            self.duplicateReceived.sort(key = lambda message: (message[0].producer.shortId, message[0].prodSeqId))
+                    
+            self.calculated = True
+                  
+        return self.duplicateSent, self.duplicateReceived
+
+    def close(self):
+        """
+        Closes the underlying file.
+        Returns nothing.
+        """
+        
+        self.file.close()
+
+    def __str__(self):
+        """
+        Returns a string representation of this object.
+        """
+        
+        return self.__path
+    

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,188 @@
+"""
+Module LogParser
+"""
+import os, sys, time
+
+from LogFile import LogFile
+from Connection import Connection
+from Producer import Producer
+from Consumer import Consumer
+from Message import Message
+
+MESSAGE_TYPES = frozenset(['ActiveMQBytesMessage', 'ActiveMQTextMessage'])
+DISPATCH_MESSAGE = 'MessageDispatch'
+ADVISORY_TEXT = 'Advisory'
+CONSUMER_TEXT = 'toConsumer:'
+
+class LogParser(object):
+    """
+    This class is in charge of parsing the log files and storing the data
+    as Connection, LogFile and Message objects.
+    """
+    
+    instance = None
+    
+    @classmethod
+    def getInstance(cls):
+        """
+        Returns the sole instance of the class.
+        """
+        
+        if cls.instance is None:
+            cls.instance = LogParser()
+        return cls.instance
+    
+    @classmethod
+    def deleteInstance(cls):
+        """
+        Deletes the sole instance of the class
+        """
+        
+        cls.instance = None
+    
+    def parse (self, logFile):
+        """
+        Parses the information in a log file.
+        logFile should be a LogFile object.
+        
+        Returns nothing.
+        """
+        try:
+            for line in logFile.file:
+                loggedMessage = line.partition('$$ ')[2]
+                if loggedMessage != '':
+                    spacedStrings = loggedMessage.split()
+                    
+                    if spacedStrings[1] == 'ConnectionInfo':
+                        connectionId = spacedStrings[3]
+                        
+                        if spacedStrings[0] == 'SENDING:':
+                            logFile.addOutgoingConnection(Connection.getConnectionByLongId(connectionId))
+                            Connection.setFrom(connectionId, logFile)
+        
+                        elif spacedStrings[0] == 'RECEIVED:':
+                            logFile.addIncomingConnection(Connection.getConnectionByLongId(connectionId))
+                            Connection.setTo(connectionId, logFile)
+                            
+                        else:
+                            raise Exception('Exception: ConnectionInfo: not SENDING or RECEIVED')
+                    
+                    elif spacedStrings[1] in MESSAGE_TYPES or spacedStrings[1] == DISPATCH_MESSAGE:
+                        timestamp = line[0:23]
+                        commaValues = spacedStrings[3].split(',')
+                        
+                        messageId = commaValues[0]
+                        producerId = messageId[:messageId.rindex(':')]
+                        
+                        connection = Connection.getConnectionByLongId(commaValues[2]) #commaValues[2] = connectionId
+                        producer = Producer.getProducerByLongId(producerId)
+                        producerConnection = Connection.getConnectionByLongId(producerId.rsplit(':', 2)[0]) #producerConnectionId
+                        message = Message.getMessage(producer,
+                                                     int(messageId[messageId.rindex(':') + 1:]), #producerSequenceId
+                                                     commaValues[-1] == ADVISORY_TEXT)
+                        
+                        producerConnection.addProducer(producer)
+                        
+                        if spacedStrings[1] in MESSAGE_TYPES:
+                            
+                            if spacedStrings[0] == 'SENDING:':
+                                
+                                direction = (logFile == connection.fromFile)
+                                connection.addSentMessage(message, direction, timestamp)
+                                logFile.addSentMessage(message, timestamp)
+                                message.addSendingConnection(connection, direction, connection,
+                                                             int(commaValues[1]), timestamp) #commaValues[1] = commandId
+                                
+                            elif spacedStrings[0] == 'RECEIVED:':
+                                
+                                direction = (logFile == connection.toFile)
+                                connection.addReceivedMessage(message, direction, timestamp)
+                                logFile.addReceivedMessage(message, timestamp)
+                                message.addReceivingConnection(connection, direction, connection,
+                                                               int(commaValues[1]), timestamp) #commaValues[1] = commandId
+                        
+                        elif spacedStrings[1] == DISPATCH_MESSAGE:
+                            
+                            #additional parsing to get the consumer
+                            consumerId = spacedStrings[4][len(CONSUMER_TEXT):]
+                            consumer = Consumer.getConsumerByLongId(consumerId)
+                            consumerConnection = Connection.getConnectionByLongId(':'.join(consumerId.split(':')[:3]))
+                            consumerConnection.addConsumer(consumer)
+                        
+                            if spacedStrings[0] == 'SENDING:':
+                                
+                                direction = (logFile == connection.fromFile)
+                                consumerConnection.addSentMessage(message, direction, timestamp)
+                                logFile.addSentMessage(message, timestamp)
+                                message.addSendingConnection(consumerConnection, direction, connection,
+                                                             int(commaValues[1]), timestamp) #commaValues[1] = commandId
+                                
+                            elif spacedStrings[0] == 'RECEIVED:':
+                                
+                                direction = (logFile == connection.toFile)
+                                consumerConnection.addReceivedMessage(message, direction, timestamp)
+                                logFile.addReceivedMessage(message, timestamp)
+                                message.addReceivingConnection(consumerConnection, direction, connection,
+                                                               int(commaValues[1]), timestamp) #commaValues[1] = commandId
+        
+        except Exception:
+            print logFile, line
+            raise
+            
+            
+    def clearData(self):
+        """
+        Clears all the data parsed.
+        """
+        
+        Connection.clearData()
+        Producer.clearData()
+        Consumer.clearData()
+        Message.clearData()
+        LogFile.clearData()
+                        
+    def parseDirectory(self, directory):
+        """
+        Parses a directory of log files.
+        """
+        
+        self.clearData()
+        
+        fileNames = os.walk(directory).next()[2]
+        logFiles = [LogFile(directory + os.sep + fileName) for fileName in fileNames]
+        
+        for logFile in logFiles:
+            self.parse(logFile)
+            
+        LogFile.closeFiles()
+        
+def main():
+    """
+    Entrance point for the command line test.
+    """
+    
+    if len(sys.argv) != 2:
+        print 'Usage: python LogParser.py directory'
+    else:
+        startTime = time.time()
+        LogParser.getInstance().parseDirectory(sys.argv[1])
+        LogParser.deleteInstance()
+        print str(Message.messageCount) + ' messages parsed'
+        print 'in ' + str(time.time() - startTime) + ' seconds'
+        
+        print 'press a key'
+        sys.stdin.read(3)
+        
+        startTime = time.time()
+        for connection in Connection.connections.itervalues():
+            connection.getErrors()
+            
+        for logFile in LogFile.logfiles:
+            logFile.getErrors()
+
+        print 'additional: ' + str(time.time() - startTime) + ' seconds'
+        time.sleep(36000)
+    
+if __name__ == '__main__':
+    main()
+    
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,120 @@
+"""
+Module Message
+"""
+
+class Message(object):
+    """
+    Objects of this class represent ActiveMQ messages.
+    They are used to store the 'travel path' of every message.
+    This class also stores a collection of all the Message objects.
+    """
+    
+    messages = {}
+    messageCount = 0
+        
+    def __init__(self, producer, prodSeqId, advisory):
+        """
+        Constructs a message object, given a producer and producer sequence id.
+        """
+        
+        self.producer = producer
+        self.prodSeqId = prodSeqId
+        self.advisory = advisory
+        self.sendingConnections = {}
+        self.receivingConnections = {}
+        
+        Message.messageCount += 1
+    
+    @classmethod
+    def clearData(cls):
+        """
+        Deletes all the messages.
+        Returns nothing.
+        """
+        
+        cls.messages.clear()
+        cls.messageCount = 0
+    
+    @classmethod
+    def getMessage(cls, producer, prodSeqId, advisory = False):
+        """
+        Returns the Message object identified by (producer, prodSeqId)
+        where producer is a producer object and prodSeqId is a producer sequence id
+        message was first sent.
+        
+        If the Message object does not exist, it will be created.
+        Returns a Message object.
+        """
+        
+        messageId = (producer, prodSeqId)
+        
+        if messageId not in cls.messages:
+            cls.messages[messageId] = Message(producer, prodSeqId, advisory)
+        
+        return cls.messages[messageId]
+    
+    @classmethod
+    def exists(cls, producer, prodSeqId):
+        """
+        Returns if there is a Message object identified by (producer, prodSeqId)
+        """
+        
+        return (producer, prodSeqId) in cls.messages
+        
+    def addSendingConnection(self, connection, direction, mostRecentConId, commandId, timestamp):
+        """
+        Adds a connection to the set of connections through which this message was sent.
+        The 'direction' argument is True if the message was sent from the file
+        connection.fromFile to the file connection.toFile, and False otherwise.
+        'timestamp' is a string with the moment this message was sent trough the connection.
+        
+        Returns nothing.
+        """
+        
+        storedConnection = (connection, direction)
+        if storedConnection in self.sendingConnections:
+            self.sendingConnections[storedConnection].append((mostRecentConId, commandId, timestamp))
+        else:
+            self.sendingConnections[storedConnection] = [(mostRecentConId, commandId, timestamp)]
+        
+    def addReceivingConnection(self, connection, direction, mostRecentConId, commandId, timestamp):
+        """
+        Adds a connection to the set of connections where this message was received.
+        The 'direction' argument is True if the message was sent from the file
+        connection.fromFile to the file connection.toFile, and False otherwise.
+        'timestamp' is a string with the moment this message was received trough the connection.
+        
+        Returns nothing.
+        """
+        
+        storedConnection = (connection, direction)
+        if storedConnection in self.receivingConnections:
+            self.receivingConnections[storedConnection].append((mostRecentConId, commandId, timestamp))
+        else:
+            self.receivingConnections[storedConnection] = [(mostRecentConId, commandId, timestamp)]
+
+    def getFiles(self):
+        """
+        Returns a 2-tuple with the following 2 sets:
+            -set of LogFile objects where this message was sent.
+            -set of LogFile objects where this message was received.
+        """
+        
+        sendingFiles = set() 
+        receivingFiles = set()
+        
+        for connection, direction in self.sendingConnections:
+            
+            if direction:
+                sendingFiles.add(connection.fromFile)
+            else:
+                sendingFiles.add(connection.toFile)
+
+        for connection, direction in self.receivingConnections:
+                        
+            if direction:
+                receivingFiles.add(connection.toFile)
+            else:
+                receivingFiles.add(connection.fromFile)
+            
+        return sendingFiles, receivingFiles
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,94 @@
+"""
+Module Producer
+"""
+
+class Producer(object):
+    """
+    This class represents an ActiveMQ Producer.
+    Each producer is identified by its long id.
+    However each producer also has a short id (an integer) to identify it more easily.
+    """
+    
+    nProducers = 0
+    producerIdList = []
+    producers = {}
+    
+    def __init__(self, longId):
+        """
+        Constructor
+        """
+        
+        self.longId = longId
+        self.shortId = Producer.nProducers
+        
+        self.connectionId, sessionId, value = longId.rsplit(':', 2)
+        self.sessionId = int(sessionId)
+        self.value = int(value)
+        
+        Producer.producers[longId] = self
+        Producer.producerIdList.append(self.longId)
+        Producer.nProducers += 1
+    
+    @classmethod
+    def clearData(cls):
+        """
+        Deletes all information read about producers.
+        
+        Returns nothing.
+        """
+        
+        cls.producers.clear()
+        cls.nProducers = 0
+        del cls.producerIdList[:]
+    
+    @classmethod
+    def getProducerByLongId(cls, longId):
+        """
+        Returns a producer given its long id.
+        If there is no producer with this long id yet, it will be created.
+        """
+        
+        if longId not in cls.producers:
+            cls.producers[longId] = Producer(longId)
+
+        return cls.producers[longId]
+    
+    @classmethod
+    def getProducerByShortId(cls, shortId):
+        """
+        Returns a producer given its short id.
+        If there is no producer with thi short id yet, IndexError will be thrown.
+        """
+        
+        return cls.producers[cls.producerIdList[shortId]]
+    
+    @classmethod
+    def exists(cls, longid):
+        """
+        Returns if a producer with the given long id exists.
+        """
+        
+        return longid in cls.producers
+    
+    @classmethod
+    def shortIdToLongId(cls, shortId):
+        """
+        Transforms a producer's short id to a long id.
+        
+        Returns a long id.
+        Throws an IndexError if the short id does not exist.
+        """
+        
+        return cls.producerIdList[shortId]
+    
+    @classmethod
+    def longIdToShortId(cls, longId):
+        """
+        Transforms a producer's long id to a short id.
+        
+        Returns a long id.
+        Throws an KeyError if the long id does not exist.
+        """
+        return cls.producers[longId].shortId
+
+        
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py?view=auto&rev=565392
==============================================================================
    (empty)

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,71 @@
+"""
+Module Application
+"""
+import wx
+from DirectoryPanel import DirectoryPanel
+from TabbedPanel import TabbedPanel
+
+class MainPanel(wx.Panel):
+    """
+    Panel contained into the window of the application.
+    It contains a DirectoryPanel and a TabbedPanel.
+    
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.Panel.__init__(self, parent, -1)
+        
+        self.tabbedPanel = TabbedPanel(self)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(DirectoryPanel(self), 0, wx.EXPAND|wx.ALL, 5)
+        sizer.Add(self.tabbedPanel, 1, wx.EXPAND)
+        self.SetSizer(sizer)
+        
+    def logDataUpdated(self):
+        """
+        Method to be called when the parsed data has been updated.
+        The Panel will notify its children components.
+        """
+        
+        self.tabbedPanel.logDataUpdated()
+
+class MainFrame(wx.Frame):
+    """
+    This class represents the window of the application.
+    It contains a MainPanel object.
+    We need to add a wx.Panel to a wx.Frame to avoid
+    graphical problems in Windows.
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.Frame.__init__(self, parent, 100, 
+                          'ActiveMQ Log Analyzer Tool', size=(1024,800))
+#        ib = wx.IconBundle()
+#        ib.AddIconFromFile("logparser.ico", wx.BITMAP_TYPE_ANY)
+#        self.SetIcons(ib)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(MainPanel(self), 1, wx.EXPAND)
+        self.SetSizer(sizer)
+        self.Centre()
+        self.Show(True)
+
+class Application(wx.App):
+    """
+    Main class of the application
+    """
+    
+    def OnInit(self):
+        """
+        To be executed when Application is launched
+        """
+        MainFrame(None)
+        return True

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,61 @@
+"""
+Module DirectoryPanel
+"""
+import wx
+import os
+
+from loganalyzerengine.LogParser import LogParser
+
+class DirectoryPanel(wx.Panel):
+    """
+    Panel to choose the directory with the log files to be parsed,
+    and launch the parsing / analyzing process.
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.Panel.__init__(self, parent, -1)
+        self.mainPanel = parent
+        self.textctrl = wx.TextCtrl(self, -1, 'C:\logs')
+        
+        self.lastDirectoryOpen = ''
+        
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(wx.StaticText(self, -1, 'Directory'), 0, wx.CENTER|wx.RIGHT, 5)
+        sizer.Add(self.textctrl, 1, wx.CENTER|wx.RIGHT, 5)
+        sizer.Add(wx.Button(self, 100 , 'Choose'), 0, wx.CENTER|wx.RIGHT, 5)
+        sizer.Add(wx.Button(self, 101 , 'Parse'), 0, wx.CENTER)
+        
+        self.Bind(wx.EVT_BUTTON, self.OnChoose, id=100)
+        self.Bind(wx.EVT_BUTTON, self.OnParse, id=101)
+        
+        self.SetSizer(sizer)
+        
+    def OnChoose(self, event):
+        """
+        Action to be executed when the 'Choose' button is pressed.
+        """
+        
+        dialog = wx.DirDialog(self, defaultPath=self.lastDirectoryOpen)
+        if dialog.ShowModal() == wx.ID_OK:
+            self.textctrl.SetValue(dialog.GetPath())
+            self.lastDirectoryOpen = dialog.GetPath()
+        else:
+            wx.MessageDialog(self, 'Please choose an appropiate directory', style=wx.OK).ShowModal()
+        
+    def OnParse(self, event):
+        """
+        Action to be executed when the 'Parse' button is pressed.
+        """
+        
+        path = self.textctrl.GetValue()
+        if os.path.isdir(path):
+            LogParser.getInstance().parseDirectory(path)
+            self.mainPanel.logDataUpdated()
+            LogParser.deleteInstance()
+        else:
+            wx.MessageDialog(self, 'That directory does not exist', style=wx.OK).ShowModal()
+    
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,184 @@
+"""
+Module IncorrectSequenceList
+"""
+import wx
+from loganalyzerengine.Connection import Connection
+from loganalyzerengine.LogFile import LogFile
+
+def advisoryString(message):
+    """
+    Helper method
+    """
+ 
+    if message.advisory:
+        return ' (ADVISORY)'
+    else:
+        return ''
+        
+
+class IncorrectSequenceList(wx.ListCtrl):
+    """
+    List of the incorrect events detected after parsing the logs.
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.ListCtrl.__init__(self, parent, -1, 
+                             style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_HRULES|wx.LC_VRULES)
+        
+        self.incorrectSequencePanel = parent
+        
+        self.datapresent = False
+        self.connectionForFilter = None
+        
+        self.InsertColumn(0, 'Type')
+        self.InsertColumn(1, 'Connection id / File')
+        self.InsertColumn(2, 'Message id (prod id | prod seq id)')
+        self.InsertColumn(3, 'ntimes')
+        self.InsertColumn(4, 'timestamps')
+        
+        self.SetColumnWidth(0, 150)
+        self.SetColumnWidth(1, 250)
+        self.SetColumnWidth(2, 300)
+        self.SetColumnWidth(3, 100)
+        self.SetColumnWidth(4, 300)
+        
+        
+    def logDataUpdated(self):
+        """
+        This method must be called to notify the list that the parsed data
+        has changed.
+        """
+
+        self.datapresent = True
+        self.updateList()
+        
+    def checkConnectionForFilter(self):
+        """
+        Returns True if the connection that was inputed by the user
+        to filter the events is valid.
+        self.connectionForFilter is a (string, boolean) tuple.
+        The boolean value is True if the string is a shortId, and False if it is a long id.
+        """
+        
+        if self.connectionForFilter is None:
+            return False
+        
+        if self.connectionForFilter[1]:
+            #shortId
+            return self.connectionForFilter[0].isdigit() and \
+                   int(self.connectionForFilter[0]) > -1 and \
+                   int(self.connectionForFilter[0]) < len(Connection.connectionIdList)
+        
+        else:
+            #longId
+            return self.connectionForFilter[0] in Connection.connections
+        
+    def updateList(self):
+        """
+        Updates the display of the list of incorrect events
+        """
+        
+        self.DeleteAllItems()
+        if self.datapresent:
+            options = self.incorrectSequencePanel.options
+            
+            row = 0
+            
+            # we construct a list of connection long ids to be displayed,
+            # depending on the filter desired
+            if self.checkConnectionForFilter():
+                if self.connectionForFilter[1]:
+                    #shortId
+                    connectionIds = [Connection.connectionIdList[int(self.connectionForFilter[0])]]
+                else:
+                    connectionIds = [self.connectionForFilter[0]]
+            else:
+                if self.connectionForFilter is None or self.connectionForFilter[0] == '':
+                    connectionIds = Connection.connections.keys()
+                else:
+                    connectionIds = []      
+                
+            # we display the problems tied to connections
+            showShortIDs = options['showShortIds']
+            
+            for longId in connectionIds:
+                
+                # we display long or short ids depending on the option chosen
+                connection = Connection.getConnectionByLongId(longId)
+                errors = connection.getErrors()
+                
+                if showShortIDs:
+                    printedConnectionId = connection.shortId
+                else:
+                    printedConnectionId = longId
+                
+                # sent but not received messages
+                if options['sentButNotReceived']:
+                    for storedMessage, n, timestamps in errors[0]:
+                        message = storedMessage[0]
+                        self.insertRow(row, 'sentButNotReceived' + advisoryString(message), printedConnectionId,
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+                
+                # received but not sent messages
+                if options['receivedButNotSent']:
+                    for storedMessage, n, timestamps in errors[1]:
+                        message = storedMessage[0]
+                        self.insertRow(row, 'receivedButNotSent' + advisoryString(message), printedConnectionId,
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+                
+                # duplicate sent or received messages through a connection
+                if options['duplicateInConnection']:
+                    for storedMessage, n, timestamps in errors[2]:
+                        message = storedMessage[0]
+                        self.insertRow(row, 'duplicateSentInConnection' + advisoryString(message), printedConnectionId,
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+                        
+                    for storedMessage, n, timestamps in errors[3]:
+                        message = storedMessage[0]
+                        self.insertRow(row, 'duplicateReceivedInConnection' + advisoryString(message), printedConnectionId,
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+            
+            # duplicate sent or received messages in the same log file.
+            # right now they are only shown when the connection filter is not used.
+            if options['duplicateInFile'] and not self.checkConnectionForFilter() and \
+            (self.connectionForFilter is None or self.connectionForFilter[0] == ''):
+                for logfile in LogFile.logfiles:
+                    errors = logfile.getErrors()
+                    
+                    for message, n, timestamps in errors[0]:
+                        self.insertRow(row, 'duplicateSentInFile' + advisoryString(message), str(logfile),
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+                        
+                    for message, n, timestamps in errors[1]:
+                        self.insertRow(row, 'duplicateReceivedInFile' + advisoryString(message), str(logfile),
+                                       message.producer.shortId if showShortIDs else message.producer.longId,
+                                       message.prodSeqId, n, timestamps, wx.WHITE)
+                        row += 1
+            
+    def insertRow(self, rownumber, typeOfError, connectionId, producerId, producerSequenceId, n, timestamps, col):
+        """
+        Helper method to insert a row into the list
+        """
+        
+        self.InsertStringItem(rownumber, typeOfError)
+        self.SetStringItem(rownumber, 1, str(connectionId))
+        self.SetStringItem(rownumber, 2, str(producerId) + ' | ' + str(producerSequenceId))
+        self.SetStringItem(rownumber, 3, str(n))
+        self.SetStringItem(rownumber, 4, ' | '.join(timestamps))
+        self.SetItemBackgroundColour(rownumber, col)
+
+        
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,135 @@
+"""
+Module IncorrectSequencePanel
+"""
+import wx
+from IncorrectSequenceList import IncorrectSequenceList
+
+class IncorrectSequencePanel(wx.Panel):
+    """
+    This panel contains a list of incorrect events dectected by the parsing,
+    and many controls to filter which events appear.
+    Also the user can change if long ids (original ActiveMQConnection id strings, long)
+    or short ids (a different integer for each connection) is desired.
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.Panel.__init__(self, parent, -1)
+        
+        self.parent = parent
+        self.options = {}
+        
+        self.incorrectSequenceList = IncorrectSequenceList(self)
+        self.showShortIds = wx.CheckBox(self, 100, 'Show results with short ids')
+        self.sentButNotReceived = wx.CheckBox(self, 101, 'Sent but not received')
+        self.receivedButNotSent = wx.CheckBox(self, 102, 'Received but not sent')
+        self.duplicateInConnection = wx.CheckBox(self, 103, 'Duplicate in connection')
+        self.duplicateInFile = wx.CheckBox(self, 104, 'Duplicate in log file')
+        self.connectionText = wx.TextCtrl(self, -1, '')
+        self.rbshortId = wx.RadioButton(self, -1, style=wx.RB_GROUP, label="Short id")
+        self.rblongId = wx.RadioButton(self, -1, label="Long id")
+        
+        self.showShortIds.SetValue(True)
+        self.sentButNotReceived.SetValue(True)
+        self.receivedButNotSent.SetValue(True)
+        self.duplicateInConnection.SetValue(True)
+        self.duplicateInFile.SetValue(True)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        sizer2 = wx.GridSizer()
+        sizer2 = wx.GridSizer(2, 2, 5, 5)
+        sizer2.AddMany([self.sentButNotReceived,
+                        self.receivedButNotSent,
+                        self.duplicateInConnection,
+                        self.duplicateInFile
+                       ])
+        
+        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
+        sizerrb = wx.BoxSizer(wx.VERTICAL)
+        sizerrb.Add(self.rbshortId, 0, wx.DOWN, 5)
+        sizerrb.Add(self.rblongId, 0)
+        sizer3.Add(wx.StaticText(self, -1, 'Filter by connection\n(leave blank to view all)'), 0, wx.CENTER|wx.RIGHT, 5)
+        sizer3.Add(self.connectionText, 1, wx.CENTER|wx.RIGHT, 5)
+        sizer3.Add(sizerrb, 0, wx.CENTER|wx.RIGHT, 5)
+        sizer3.Add(wx.Button(self, 105, 'Filter'), 0, wx.CENTER)
+        
+        sizer4 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer4.Add(sizer2, 0, wx.CENTER)
+        sizer4.Add(sizer3, 1, wx.EXPAND|wx.CENTER|wx.LEFT, 20)
+        
+        sizer.Add(sizer4, 0, wx.EXPAND|wx.ALL, 5)
+        
+        sizer5 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer5.Add(self.showShortIds, 0, wx.RIGHT|wx.CENTER, 5)
+        sizer5.Add(wx.Button(self, 106, 'Jump to Message Browsing'), 0, wx.CENTER)
+        
+        sizer.Add(sizer5, 0, wx.ALL, 5)
+        
+        sizer.Add(self.incorrectSequenceList, 1, wx.EXPAND)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=100)
+        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=101)
+        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=102)
+        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=103)
+        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=104)
+        self.Bind(wx.EVT_BUTTON, self.OnFilter, id=105)
+        self.Bind(wx.EVT_BUTTON, self.OnJump, id=106)
+        
+        self.parseOptions()
+        
+        self.SetSizer(sizer)
+        
+    def logDataUpdated(self):
+        """
+        This method must be called to notify the panel that the parsed data has been updated.
+        It will in turn notify the list.
+        """
+        
+        self.incorrectSequenceList.logDataUpdated()
+        
+    def parseOptions(self):
+        """
+        Stores the values of the various checkboxes into self.options.
+        """
+        
+        self.options['showShortIds'] = self.showShortIds.IsChecked()
+        self.options['sentButNotReceived'] = self.sentButNotReceived.IsChecked() 
+        self.options['receivedButNotSent'] = self.receivedButNotSent.IsChecked()
+        self.options['duplicateInConnection'] = self.duplicateInConnection.IsChecked()
+        self.options['duplicateInFile'] = self.duplicateInFile.IsChecked()
+    
+    def OptionsChanged(self, event):
+        """
+        Action to be executed every time one of the checkboxes is clicked.
+        It calls parseOptions() and then updates the display of incorrect events.
+        """
+        
+        self.parseOptions()
+        self.incorrectSequenceList.updateList()
+        
+    def OnFilter(self, event):
+        """
+        Action to be executed every time the button 'filter' is pressed.
+        """
+        
+        self.incorrectSequenceList.connectionForFilter = (self.connectionText.GetValue(), self.rbshortId.GetValue())
+        self.OptionsChanged(event)
+        
+    def OnJump(self, event):
+        """
+        Action to be executed when the 'jump' button is pressed.
+        """
+        
+        if self.incorrectSequenceList.GetFirstSelected() != -1:
+            connectionId, messageId = self.incorrectSequenceList.GetItem(self.incorrectSequenceList.GetFirstSelected(), 2).GetText().split(' | ')
+            self.parent.GetParent().browsingMessagesPanel.textctrl1.SetValue(connectionId)
+            self.parent.GetParent().browsingMessagesPanel.textctrl2.SetValue(messageId)
+            self.parent.GetParent().browsingMessagesPanel.rbshortId.SetValue(self.showShortIds.GetValue())
+            self.parent.GetParent().browsingMessagesPanel.rblongId.SetValue(not self.showShortIds.GetValue())
+            self.parent.GetParent().browsingMessagesPanel.displayMessageInfo(event)
+        
+            self.parent.SetSelection(1)
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py?view=auto&rev=565392
==============================================================================
--- activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py (added)
+++ activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py Mon Aug 13 09:03:25 2007
@@ -0,0 +1,66 @@
+"""
+Module MessageTravelPanel
+"""
+import wx
+from MessageTravelText import MessageTravelText
+
+class MessageTravelPanel(wx.Panel):
+    """
+    The function of this panel is to show the travel history of a message.
+    This means the connections that the message went through.
+    """
+    
+    def __init__(self, parent):
+        """
+        Constructor
+        """
+        
+        wx.Panel.__init__(self, parent, -1)
+        
+        self.rbshortId = wx.RadioButton(self, -1, style=wx.RB_GROUP, label="Short id")
+        self.rblongId = wx.RadioButton(self, -1, label="Long id")
+        self.textctrl1 = wx.TextCtrl(self, -1, '')
+        self.textctrl2 = wx.TextCtrl(self, -1, '')
+        self.chkshowshortId = wx.CheckBox(self, 100, 'Show result with short ids')
+        self.messageTravelPanel = MessageTravelText(self)
+        
+        self.chkshowshortId.SetValue(True)
+        
+        sizerrb = wx.BoxSizer(wx.VERTICAL)
+        sizerrb.Add(self.rbshortId, 0, wx.DOWN, 5)
+        sizerrb.Add(self.rblongId, 0)
+        
+        sizerinput = wx.BoxSizer(wx.HORIZONTAL)
+        sizerinput.Add(sizerrb, 0, wx.RIGHT, 5)
+        sizerinput.Add(wx.StaticText(self, -1, 'Producer id'), 0, wx.CENTER|wx.RIGHT, 5)
+        sizerinput.Add(self.textctrl1, 2, wx.CENTER|wx.RIGHT, 5)
+        sizerinput.Add(wx.StaticText(self, -1, 'Producer Sequence id'), 0, wx.CENTER|wx.RIGHT, 5)
+        sizerinput.Add(self.textctrl2, 1, wx.CENTER|wx.RIGHT, 5)
+        sizerinput.Add(wx.Button(self, 101 , 'Browse'), 0, wx.CENTER)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(sizerinput, 0, wx.EXPAND|wx.ALL, 5)
+        sizer.Add(self.chkshowshortId, 0, wx.LEFT|wx.UP, 5)
+        sizer.Add(self.messageTravelPanel, 1, wx.EXPAND|wx.ALL, 5)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.displayMessageInfo, id=100)
+        self.Bind(wx.EVT_BUTTON, self.displayMessageInfo, id=101)
+        
+        self.SetSizer(sizer)
+    
+    def displayMessageInfo(self, event):
+        """
+        Action to be executed when the 'Browse' button is pushed.
+        """
+        
+        self.messageTravelPanel.displayMessageInfo(self.textctrl1.GetValue(),
+                                                 self.textctrl2.GetValue(),
+                                                 self.rbshortId.GetValue())
+        
+    def logDataUpdated(self):
+        """
+        This method must be called to notify the panel that the parsed data has been updated.
+        It will in turn notify the message travel panel.
+        """
+        
+        self.messageTravelPanel.logDataUpdated()
\ No newline at end of file

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc?view=auto&rev=565392
==============================================================================
Binary file - no diff available.

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
------------------------------------------------------------------------------
    svn:executable = *

Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



Re: svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/

Posted by Rob Davies <ra...@gmail.com>.
oops - read too quickly - will remove the *.pyc files only :)

On Aug 13, 2007, at 9:31 PM, Albert Strasheim wrote:

> Hello
>
> The *.pyc files probably shouldn't be in the repository.
>
> Regards,
>
> Albert
>
> ----- Original Message ----- From: <ra...@apache.org>
> To: <co...@activemq.apache.org>
> Sent: Monday, August 13, 2007 6:03 PM
> Subject: svn commit: r565392 [1/2] - in /activemq/trunk/ 
> log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/
>
>
>> Author: rajdavies
>> Date: Mon Aug 13 09:03:25 2007
>> New Revision: 565392
>>
>> URL: http://svn.apache.org/viewvc?view=rev&rev=565392
>> Log:
>> Added the log analyser tool to svn - for http://issues.apache.org/ 
>> activemq/browse/AMQ-1361
>>
>> Added:
>>    activemq/trunk/log_analyzer_tool/
>>    activemq/trunk/log_analyzer_tool/Main.py   (with props)
>>    activemq/trunk/log_analyzer_tool/README.txt   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Connection.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Connection.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Consumer.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Consumer.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogFile.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogParser.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogParser.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Message.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Producer.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Producer.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> __init__.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> __init__.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> Application.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> Application.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> DirectoryPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> DirectoryPanel.pyc (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequenceList.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequenceList.pyc (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequencePanel.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequencePanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelText.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelText.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> TabbedPanel.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> TabbedPanel.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewClientsPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewClientsPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewConnectionsPanel.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewConnectionsPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewFilesPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewFilesPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.pyc    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/run.bat   (with props)
>>    activemq/trunk/log_analyzer_tool/run.sh   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/
>>    activemq/trunk/log_analyzer_tool/screenshots/1.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/2.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/3.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/4.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/5.png   (with props)
>


Re: svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/

Posted by Rob Davies <ra...@gmail.com>.
ok - will remove - any suggestions on a good home ?

On Aug 13, 2007, at 9:31 PM, Albert Strasheim wrote:

> Hello
>
> The *.pyc files probably shouldn't be in the repository.
>
> Regards,
>
> Albert
>
> ----- Original Message ----- From: <ra...@apache.org>
> To: <co...@activemq.apache.org>
> Sent: Monday, August 13, 2007 6:03 PM
> Subject: svn commit: r565392 [1/2] - in /activemq/trunk/ 
> log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/
>
>
>> Author: rajdavies
>> Date: Mon Aug 13 09:03:25 2007
>> New Revision: 565392
>>
>> URL: http://svn.apache.org/viewvc?view=rev&rev=565392
>> Log:
>> Added the log analyser tool to svn - for http://issues.apache.org/ 
>> activemq/browse/AMQ-1361
>>
>> Added:
>>    activemq/trunk/log_analyzer_tool/
>>    activemq/trunk/log_analyzer_tool/Main.py   (with props)
>>    activemq/trunk/log_analyzer_tool/README.txt   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Connection.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Connection.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Consumer.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Consumer.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogFile.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogParser.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> LogParser.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Message.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Producer.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> Producer.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> __init__.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzerengine/ 
>> __init__.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> Application.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> Application.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> DirectoryPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> DirectoryPanel.pyc (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequenceList.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequenceList.pyc (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequencePanel.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> IncorrectSequencePanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelText.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> MessageTravelText.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> TabbedPanel.py   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> TabbedPanel.pyc   (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewClientsPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewClientsPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewConnectionsPanel.py (with props)
>> activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewConnectionsPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewFilesPanel.py (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/ 
>> ViewFilesPanel.pyc (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.py    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.pyc    
>> (with props)
>>    activemq/trunk/log_analyzer_tool/run.bat   (with props)
>>    activemq/trunk/log_analyzer_tool/run.sh   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/
>>    activemq/trunk/log_analyzer_tool/screenshots/1.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/2.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/3.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/4.png   (with props)
>>    activemq/trunk/log_analyzer_tool/screenshots/5.png   (with props)
>


Re: svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/

Posted by Albert Strasheim <fu...@gmail.com>.
Hello

The *.pyc files probably shouldn't be in the repository.

Regards,

Albert

----- Original Message ----- 
From: <ra...@apache.org>
To: <co...@activemq.apache.org>
Sent: Monday, August 13, 2007 6:03 PM
Subject: svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: 
./ loganalyzerengine/ loganalyzergui/ screenshots/


> Author: rajdavies
> Date: Mon Aug 13 09:03:25 2007
> New Revision: 565392
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=565392
> Log:
> Added the log analyser tool to svn - for 
> http://issues.apache.org/activemq/browse/AMQ-1361
>
> Added:
>    activemq/trunk/log_analyzer_tool/
>    activemq/trunk/log_analyzer_tool/Main.py   (with props)
>    activemq/trunk/log_analyzer_tool/README.txt   (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/
>    activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc 
> (with props)
> 
> activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py 
> (with props)
> 
> activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc 
> (with props)
> 
> activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py 
> (with props)
> 
> activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.py 
> (with props)
> 
> activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.py 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.pyc 
> (with props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.py   (with 
> props)
>    activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.pyc   (with 
> props)
>    activemq/trunk/log_analyzer_tool/run.bat   (with props)
>    activemq/trunk/log_analyzer_tool/run.sh   (with props)
>    activemq/trunk/log_analyzer_tool/screenshots/
>    activemq/trunk/log_analyzer_tool/screenshots/1.png   (with props)
>    activemq/trunk/log_analyzer_tool/screenshots/2.png   (with props)
>    activemq/trunk/log_analyzer_tool/screenshots/3.png   (with props)
>    activemq/trunk/log_analyzer_tool/screenshots/4.png   (with props)
>    activemq/trunk/log_analyzer_tool/screenshots/5.png   (with props)


Re: svn commit: r565392 [1/2] - in /activemq/trunk/log_analyzer_tool: ./ loganalyzerengine/ loganalyzergui/ screenshots/

Posted by Hiram Chirino <hi...@hiramchirino.com>.
Apache Headers???

On 8/13/07, rajdavies@apache.org <ra...@apache.org> wrote:
> Author: rajdavies
> Date: Mon Aug 13 09:03:25 2007
> New Revision: 565392
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=565392
> Log:
> Added the log analyser tool to svn - for http://issues.apache.org/activemq/browse/AMQ-1361
>
> Added:
>     activemq/trunk/log_analyzer_tool/
>     activemq/trunk/log_analyzer_tool/Main.py   (with props)
>     activemq/trunk/log_analyzer_tool/README.txt   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/
>     activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelText.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/TabbedPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewClientsPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewConnectionsPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/ViewFilesPanel.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.py   (with props)
>     activemq/trunk/log_analyzer_tool/loganalyzergui/__init__.pyc   (with props)
>     activemq/trunk/log_analyzer_tool/run.bat   (with props)
>     activemq/trunk/log_analyzer_tool/run.sh   (with props)
>     activemq/trunk/log_analyzer_tool/screenshots/
>     activemq/trunk/log_analyzer_tool/screenshots/1.png   (with props)
>     activemq/trunk/log_analyzer_tool/screenshots/2.png   (with props)
>     activemq/trunk/log_analyzer_tool/screenshots/3.png   (with props)
>     activemq/trunk/log_analyzer_tool/screenshots/4.png   (with props)
>     activemq/trunk/log_analyzer_tool/screenshots/5.png   (with props)
>
> Added: activemq/trunk/log_analyzer_tool/Main.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/Main.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/Main.py (added)
> +++ activemq/trunk/log_analyzer_tool/Main.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,14 @@
> +"""
> +Module Main
> +"""
> +from loganalyzergui.Application import Application
> +
> +def main():
> +    """
> +    Entrance point for the application
> +    """
> +    app = Application(0)
> +    app.MainLoop()
> +
> +if __name__ == '__main__':
> +    main()
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/Main.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/README.txt
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/README.txt?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/README.txt (added)
> +++ activemq/trunk/log_analyzer_tool/README.txt Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,64 @@
> +Readme file for the LogAnalyzer application.
> +
> +1. Requirements:
> +-Python 2.5.1 (http://www.python.org/download/releases/2.5.1/ or your favorite package)
> +-wxPython 2.8.4 (http://www.wxpython.org/download.php or your favorite package)
> +
> +2. How to execute:
> +Run 'python Main.py'.
> +
> +3. Some instructions:
> +-This tool will analyze ActiveMQ log files that have been produced
> +using the 'custom' transport log format. To analyze the files,
> +put them in a directory, choose that directory and click 'Parse'.
> +Please don't put any other kind of files in the same directory
> +(sub-directories won't cause any problem, but the files inside
> +them will not be analyzed).
> +For example, imagine you have a setup with 4 machines: 1 has producers,
> +2 are brokers, and 1 has consumers. As long as you have 1 JVM per machine,
> +you should have 4 log files. Call the files p.log, b1.log, b2.log,
> +and c.log, for example. Put the 4 files in the same directory,
> +choose that directory and click the 'Parse' button.
> +
> +-The first tab of the tool shows incorrect situations at transport level:
> +(i) Messages that were sent through a connection, but were not received
> +at the other end.
> +(ii) Messages that were received through a connection, but were not sent
> +(probably you are missing the log file of the JVM that sent the message).
> +(iii) Messages that are sent 2 times through the same connection.
> +(iv) Messages that were sent 2 times by the same JVM, but through
> +different connections.
> +By clicking the 'Show results with short ids' checkbox, you can switch
> +between the real connection / producer id used by ActiveMQ,
> +or a unique integer assigned by the tool.
> +Often it's easier to compare and browse with this integers than with
> +the original id's which are often long strings.
> +The 'Message id' column shows 2 things: the id of the producer that
> +originally issued the message, and the 'Producer Sequence Id' of a message.
> +These 2 items identify a message in a unique way.
> +
> +You can use the checkboxes to filter per type.
> +You can also filter by a given connection (but then problems of type (iv)
> +will not appear because they 'belong' to more than one connection).
> +You can input a 'long id' (the original ActiveMQ id) or a 'short id'
> +(a short integer assigned by the tool to each connection).
> +
> +-The second tab of the tool allows you to get a lot of information
> +about a single message. Input the producer id of the original producer
> +of the message, and the message's 'Producer Sequence Id'.
> +You can choose to use the original ActiveMQ producer id (long id)
> +or the short integer assigned to a producer by the tool.
> +You can also use the 'Jump to Message Browsing' button of the 1st tab
> +to see the information about the problems of a given message
> +without having to copy the message id manually.
> +In this tab you can also use the 'Show results with short ids' checkbox.
> +
> +-The third tab gives a summary of the clients (producer and consumers)
> +which appear in the log files. Each client is identified by a short id,
> +and belongs to a connection (whose 'short id' and 'long id' are shown).
> +
> +-The fourth tab gives a summary of the connections involved,
> +and the clients that belong to them.
> +
> +-The fifth tab gives a summary of the log files analyzed,
> +and the connections in each of the files.
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/README.txt
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Propchange: activemq/trunk/log_analyzer_tool/README.txt
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,337 @@
> +"""
> +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)])
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Connection.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,76 @@
> +"""
> +Module Consumer
> +"""
> +
> +class Consumer(object):
> +    """
> +    This class represents an ActiveMQ Consumer.
> +    Each consumer is identified by its long id.
> +    However each consumer also has a short id (an integer) to identify it more easily.
> +    """
> +
> +    nConsumers = 0
> +    consumerIdList = []
> +    consumers = {}
> +
> +    def __init__(self, longId):
> +        """
> +        Constructor
> +        """
> +
> +        self.longId = longId
> +        self.shortId = Consumer.nConsumers
> +
> +        self.connectionId, sessionId, value = longId.rsplit(':', 2)
> +        self.sessionId = int(sessionId)
> +        self.value = int(value)
> +
> +        Consumer.consumers[longId] = self
> +        Consumer.consumerIdList.append(self.longId)
> +        Consumer.nConsumers += 1
> +
> +    @classmethod
> +    def clearData(cls):
> +        """
> +        Deletes all information read about Consumers.
> +
> +        Returns nothing.
> +        """
> +
> +        cls.consumers.clear()
> +        cls.nConsumers = 0
> +        del cls.consumerIdList[:]
> +
> +    @classmethod
> +    def getConsumerByLongId(cls, longId):
> +        """
> +        Returns a consumer given its long id.
> +        If there is no consumer with this long id yet, it will be created.
> +        """
> +
> +        if longId not in cls.consumers:
> +            cls.consumers[longId] = Consumer(longId)
> +
> +        return cls.consumers[longId]
> +
> +    @classmethod
> +    def shortIdToLongId(cls, shortId):
> +        """
> +        Transforms a consumer's short id to a long id.
> +
> +        Returns a long id.
> +        Throws an IndexError if the short id does not exist.
> +        """
> +
> +        return cls.consumerIdList[shortId]
> +
> +    @classmethod
> +    def longIdToShortId(cls, longId):
> +        """
> +        Transforms a consumer's long id to a short id.
> +
> +        Returns a long id.
> +        Throws an KeyError if the long id does not exist.
> +        """
> +        return cls.consumers[longId].shortId
> +
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Consumer.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,187 @@
> +"""
> +Module LogFile
> +"""
> +import os
> +
> +class LogFile(object):
> +    """
> +    Class that represents an ActiveMQ log file read by the application.
> +    It also stores a list of all the LogFile objects.
> +
> +    A LogFile object stores the following information:
> +    -A list of 'outgoing' Connection objects that represent the connections
> +    created by the JVM that writes this LogFile.
> +    -A list of 'incoming' Connection objects that represent the connections
> +    requests received by the JVM that writes this LogFile.
> +
> +    -A dictionary of messages that were sent in this file.
> +    The keys are Message objects and the values
> +    are lists of timestamps of when the message was sent.
> +    -A list of messages that were received in this file.
> +    The keys are Message objects and the values
> +    are lists of timestamps of when the message was received.
> +
> +    -A list of messages that were sent in this file more than 1 time (duplicates)
> +    The list is made of (message, ntimes, timestamps) tuples.
> +    -A list of messages that were received in this file more than 1 time (duplicates),
> +    analogous to the previous structure.
> +    """
> +
> +    logfiles = []
> +
> +    def __init__(self, path):
> +        """
> +        Constructs a LogFile object.
> +        path: a string with the path to the ActiveMQ log file.
> +        """
> +
> +        self.__path = os.path.abspath(path)
> +        self.file = open(self.__path, 'r')
> +        self.outgoing = []
> +        self.incoming = []
> +
> +        self.sent = {}
> +        self.received = {}
> +
> +        self.duplicateReceived = None
> +        self.duplicateSent = None
> +
> +        self.calculated = False
> +
> +        LogFile.logfiles.append(self)
> +
> +    @classmethod
> +    def clearData(cls):
> +        """
> +        Class method erases all the LogFile objects stored in the LogFile class.
> +        Returns nothing.
> +        """
> +
> +        del cls.logfiles[:]
> +
> +    @classmethod
> +    def closeFiles(cls):
> +        """
> +        Class method that closes all the LogFile objects stored in the LogFile class.
> +        Returns nothing.
> +        """
> +
> +        for logFile in cls.logfiles:
> +            logFile.file.close()
> +
> +
> +
> +    def addOutgoingConnection(self, con):
> +        """
> +        Adds an 'outgoing' Connection object to this LogFile.
> +        Returns nothing.
> +        """
> +
> +        self.outgoing.append(con)
> +
> +    def addIncomingConnection(self, con):
> +        """
> +        Adds an 'incoming' Connection object to this LogFile.
> +        Returns nothing.
> +        """
> +
> +        self.incoming.append(con)
> +
> +    def addSentMessage(self, message, timestamp):
> +        """
> +        Adds a message to the set of messages that were sent thtough this file.
> +        If a message gets sent 2 times, it gets added to the set of duplicate sent messages.
> +        message: a Message object.
> +        timestamp: a string with the time where this message was sent.
> +
> +        Returns nothing.
> +        """
> +
> +        if message in self.sent:
> +            self.sent[message].append(timestamp)
> +        else:
> +            self.sent[message] = [timestamp]
> +
> +    def addReceivedMessage(self, message, timestamp):
> +        """
> +        Adds a message to the set of messages that were received in this file.
> +        If a message gets sent 2 times, it gets added to the set of duplicate received messages.
> +        message: a Message object.
> +        timestamp: a string with the time where this message was sent.
> +
> +        Returns nothing.
> +        """
> +
> +        #message = (shortProdId, prodSeqId, False)
> +        if message in self.received:
> +            self.received[message].append(timestamp)
> +        else:
> +            self.received[message] = [timestamp]
> +
> +    def getErrors(self):
> +        """
> +        Returns a 2-tuple with:
> +            -a list of (message, ntimes, timestamps) tuples, with the duplicate sent messages
> +            that appear in more than one connection in this file.
> +            'message' is a Message object.
> +            'ntimes' is an integer stating how many times the message was sent ( always >= 2)
> +            'timestamps' is a list of timestamps with the instants the message was sent.
> +
> +            -a list of (message, ntimes, timestamps) tuples, with the duplicate received messages
> +            that appear in more than one connection in this file.
> +            Structure analogous to previous one.
> +
> +        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:
> +
> +            duplicateSentTemp = [(message, len(timestamps), timestamps)
> +                                 for message, timestamps in self.sent.iteritems() if len(timestamps) > 1]
> +            self.duplicateSent = []
> +
> +            for message, _, timestamps in duplicateSentTemp:
> +                connections = []
> +                for connection, direction in message.sendingConnections:
> +                    if direction and connection.fromFile == self       \
> +                    or not direction and connection.toFile == self:
> +                        connections.append(connection)
> +                if len(connections) > 1:
> +                    self.duplicateSent.append((message, len(timestamps), timestamps))
> +
> +            duplicateReceivedTemp = [(message, len(timestamps), timestamps)
> +                                      for message, timestamps in self.received.iteritems() if len(timestamps) > 1]
> +            self.duplicateReceived = []
> +
> +            for message, _, timestamps in duplicateReceivedTemp:
> +                connections = []
> +                for connection, direction in message.receivingConnections:
> +                    if direction and connection.toFile == self       \
> +                    or not direction and connection.fromFile == self:
> +                        connections.append(connection)
> +                if len(connections) > 1:
> +                    self.duplicateReceived.append((message, len(timestamps), timestamps))
> +
> +            self.duplicateSent.sort(key = lambda message: (message[0].producer.shortId, message[0].prodSeqId))
> +            self.duplicateReceived.sort(key = lambda message: (message[0].producer.shortId, message[0].prodSeqId))
> +
> +            self.calculated = True
> +
> +        return self.duplicateSent, self.duplicateReceived
> +
> +    def close(self):
> +        """
> +        Closes the underlying file.
> +        Returns nothing.
> +        """
> +
> +        self.file.close()
> +
> +    def __str__(self):
> +        """
> +        Returns a string representation of this object.
> +        """
> +
> +        return self.__path
> +
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogFile.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,188 @@
> +"""
> +Module LogParser
> +"""
> +import os, sys, time
> +
> +from LogFile import LogFile
> +from Connection import Connection
> +from Producer import Producer
> +from Consumer import Consumer
> +from Message import Message
> +
> +MESSAGE_TYPES = frozenset(['ActiveMQBytesMessage', 'ActiveMQTextMessage'])
> +DISPATCH_MESSAGE = 'MessageDispatch'
> +ADVISORY_TEXT = 'Advisory'
> +CONSUMER_TEXT = 'toConsumer:'
> +
> +class LogParser(object):
> +    """
> +    This class is in charge of parsing the log files and storing the data
> +    as Connection, LogFile and Message objects.
> +    """
> +
> +    instance = None
> +
> +    @classmethod
> +    def getInstance(cls):
> +        """
> +        Returns the sole instance of the class.
> +        """
> +
> +        if cls.instance is None:
> +            cls.instance = LogParser()
> +        return cls.instance
> +
> +    @classmethod
> +    def deleteInstance(cls):
> +        """
> +        Deletes the sole instance of the class
> +        """
> +
> +        cls.instance = None
> +
> +    def parse (self, logFile):
> +        """
> +        Parses the information in a log file.
> +        logFile should be a LogFile object.
> +
> +        Returns nothing.
> +        """
> +        try:
> +            for line in logFile.file:
> +                loggedMessage = line.partition('$$ ')[2]
> +                if loggedMessage != '':
> +                    spacedStrings = loggedMessage.split()
> +
> +                    if spacedStrings[1] == 'ConnectionInfo':
> +                        connectionId = spacedStrings[3]
> +
> +                        if spacedStrings[0] == 'SENDING:':
> +                            logFile.addOutgoingConnection(Connection.getConnectionByLongId(connectionId))
> +                            Connection.setFrom(connectionId, logFile)
> +
> +                        elif spacedStrings[0] == 'RECEIVED:':
> +                            logFile.addIncomingConnection(Connection.getConnectionByLongId(connectionId))
> +                            Connection.setTo(connectionId, logFile)
> +
> +                        else:
> +                            raise Exception('Exception: ConnectionInfo: not SENDING or RECEIVED')
> +
> +                    elif spacedStrings[1] in MESSAGE_TYPES or spacedStrings[1] == DISPATCH_MESSAGE:
> +                        timestamp = line[0:23]
> +                        commaValues = spacedStrings[3].split(',')
> +
> +                        messageId = commaValues[0]
> +                        producerId = messageId[:messageId.rindex(':')]
> +
> +                        connection = Connection.getConnectionByLongId(commaValues[2]) #commaValues[2] = connectionId
> +                        producer = Producer.getProducerByLongId(producerId)
> +                        producerConnection = Connection.getConnectionByLongId(producerId.rsplit(':', 2)[0]) #producerConnectionId
> +                        message = Message.getMessage(producer,
> +                                                     int(messageId[messageId.rindex(':') + 1:]), #producerSequenceId
> +                                                     commaValues[-1] == ADVISORY_TEXT)
> +
> +                        producerConnection.addProducer(producer)
> +
> +                        if spacedStrings[1] in MESSAGE_TYPES:
> +
> +                            if spacedStrings[0] == 'SENDING:':
> +
> +                                direction = (logFile == connection.fromFile)
> +                                connection.addSentMessage(message, direction, timestamp)
> +                                logFile.addSentMessage(message, timestamp)
> +                                message.addSendingConnection(connection, direction, connection,
> +                                                             int(commaValues[1]), timestamp) #commaValues[1] = commandId
> +
> +                            elif spacedStrings[0] == 'RECEIVED:':
> +
> +                                direction = (logFile == connection.toFile)
> +                                connection.addReceivedMessage(message, direction, timestamp)
> +                                logFile.addReceivedMessage(message, timestamp)
> +                                message.addReceivingConnection(connection, direction, connection,
> +                                                               int(commaValues[1]), timestamp) #commaValues[1] = commandId
> +
> +                        elif spacedStrings[1] == DISPATCH_MESSAGE:
> +
> +                            #additional parsing to get the consumer
> +                            consumerId = spacedStrings[4][len(CONSUMER_TEXT):]
> +                            consumer = Consumer.getConsumerByLongId(consumerId)
> +                            consumerConnection = Connection.getConnectionByLongId(':'.join(consumerId.split(':')[:3]))
> +                            consumerConnection.addConsumer(consumer)
> +
> +                            if spacedStrings[0] == 'SENDING:':
> +
> +                                direction = (logFile == connection.fromFile)
> +                                consumerConnection.addSentMessage(message, direction, timestamp)
> +                                logFile.addSentMessage(message, timestamp)
> +                                message.addSendingConnection(consumerConnection, direction, connection,
> +                                                             int(commaValues[1]), timestamp) #commaValues[1] = commandId
> +
> +                            elif spacedStrings[0] == 'RECEIVED:':
> +
> +                                direction = (logFile == connection.toFile)
> +                                consumerConnection.addReceivedMessage(message, direction, timestamp)
> +                                logFile.addReceivedMessage(message, timestamp)
> +                                message.addReceivingConnection(consumerConnection, direction, connection,
> +                                                               int(commaValues[1]), timestamp) #commaValues[1] = commandId
> +
> +        except Exception:
> +            print logFile, line
> +            raise
> +
> +
> +    def clearData(self):
> +        """
> +        Clears all the data parsed.
> +        """
> +
> +        Connection.clearData()
> +        Producer.clearData()
> +        Consumer.clearData()
> +        Message.clearData()
> +        LogFile.clearData()
> +
> +    def parseDirectory(self, directory):
> +        """
> +        Parses a directory of log files.
> +        """
> +
> +        self.clearData()
> +
> +        fileNames = os.walk(directory).next()[2]
> +        logFiles = [LogFile(directory + os.sep + fileName) for fileName in fileNames]
> +
> +        for logFile in logFiles:
> +            self.parse(logFile)
> +
> +        LogFile.closeFiles()
> +
> +def main():
> +    """
> +    Entrance point for the command line test.
> +    """
> +
> +    if len(sys.argv) != 2:
> +        print 'Usage: python LogParser.py directory'
> +    else:
> +        startTime = time.time()
> +        LogParser.getInstance().parseDirectory(sys.argv[1])
> +        LogParser.deleteInstance()
> +        print str(Message.messageCount) + ' messages parsed'
> +        print 'in ' + str(time.time() - startTime) + ' seconds'
> +
> +        print 'press a key'
> +        sys.stdin.read(3)
> +
> +        startTime = time.time()
> +        for connection in Connection.connections.itervalues():
> +            connection.getErrors()
> +
> +        for logFile in LogFile.logfiles:
> +            logFile.getErrors()
> +
> +        print 'additional: ' + str(time.time() - startTime) + ' seconds'
> +        time.sleep(36000)
> +
> +if __name__ == '__main__':
> +    main()
> +
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/LogParser.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,120 @@
> +"""
> +Module Message
> +"""
> +
> +class Message(object):
> +    """
> +    Objects of this class represent ActiveMQ messages.
> +    They are used to store the 'travel path' of every message.
> +    This class also stores a collection of all the Message objects.
> +    """
> +
> +    messages = {}
> +    messageCount = 0
> +
> +    def __init__(self, producer, prodSeqId, advisory):
> +        """
> +        Constructs a message object, given a producer and producer sequence id.
> +        """
> +
> +        self.producer = producer
> +        self.prodSeqId = prodSeqId
> +        self.advisory = advisory
> +        self.sendingConnections = {}
> +        self.receivingConnections = {}
> +
> +        Message.messageCount += 1
> +
> +    @classmethod
> +    def clearData(cls):
> +        """
> +        Deletes all the messages.
> +        Returns nothing.
> +        """
> +
> +        cls.messages.clear()
> +        cls.messageCount = 0
> +
> +    @classmethod
> +    def getMessage(cls, producer, prodSeqId, advisory = False):
> +        """
> +        Returns the Message object identified by (producer, prodSeqId)
> +        where producer is a producer object and prodSeqId is a producer sequence id
> +        message was first sent.
> +
> +        If the Message object does not exist, it will be created.
> +        Returns a Message object.
> +        """
> +
> +        messageId = (producer, prodSeqId)
> +
> +        if messageId not in cls.messages:
> +            cls.messages[messageId] = Message(producer, prodSeqId, advisory)
> +
> +        return cls.messages[messageId]
> +
> +    @classmethod
> +    def exists(cls, producer, prodSeqId):
> +        """
> +        Returns if there is a Message object identified by (producer, prodSeqId)
> +        """
> +
> +        return (producer, prodSeqId) in cls.messages
> +
> +    def addSendingConnection(self, connection, direction, mostRecentConId, commandId, timestamp):
> +        """
> +        Adds a connection to the set of connections through which this message was sent.
> +        The 'direction' argument is True if the message was sent from the file
> +        connection.fromFile to the file connection.toFile, and False otherwise.
> +        'timestamp' is a string with the moment this message was sent trough the connection.
> +
> +        Returns nothing.
> +        """
> +
> +        storedConnection = (connection, direction)
> +        if storedConnection in self.sendingConnections:
> +            self.sendingConnections[storedConnection].append((mostRecentConId, commandId, timestamp))
> +        else:
> +            self.sendingConnections[storedConnection] = [(mostRecentConId, commandId, timestamp)]
> +
> +    def addReceivingConnection(self, connection, direction, mostRecentConId, commandId, timestamp):
> +        """
> +        Adds a connection to the set of connections where this message was received.
> +        The 'direction' argument is True if the message was sent from the file
> +        connection.fromFile to the file connection.toFile, and False otherwise.
> +        'timestamp' is a string with the moment this message was received trough the connection.
> +
> +        Returns nothing.
> +        """
> +
> +        storedConnection = (connection, direction)
> +        if storedConnection in self.receivingConnections:
> +            self.receivingConnections[storedConnection].append((mostRecentConId, commandId, timestamp))
> +        else:
> +            self.receivingConnections[storedConnection] = [(mostRecentConId, commandId, timestamp)]
> +
> +    def getFiles(self):
> +        """
> +        Returns a 2-tuple with the following 2 sets:
> +            -set of LogFile objects where this message was sent.
> +            -set of LogFile objects where this message was received.
> +        """
> +
> +        sendingFiles = set()
> +        receivingFiles = set()
> +
> +        for connection, direction in self.sendingConnections:
> +
> +            if direction:
> +                sendingFiles.add(connection.fromFile)
> +            else:
> +                sendingFiles.add(connection.toFile)
> +
> +        for connection, direction in self.receivingConnections:
> +
> +            if direction:
> +                receivingFiles.add(connection.toFile)
> +            else:
> +                receivingFiles.add(connection.fromFile)
> +
> +        return sendingFiles, receivingFiles
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Message.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,94 @@
> +"""
> +Module Producer
> +"""
> +
> +class Producer(object):
> +    """
> +    This class represents an ActiveMQ Producer.
> +    Each producer is identified by its long id.
> +    However each producer also has a short id (an integer) to identify it more easily.
> +    """
> +
> +    nProducers = 0
> +    producerIdList = []
> +    producers = {}
> +
> +    def __init__(self, longId):
> +        """
> +        Constructor
> +        """
> +
> +        self.longId = longId
> +        self.shortId = Producer.nProducers
> +
> +        self.connectionId, sessionId, value = longId.rsplit(':', 2)
> +        self.sessionId = int(sessionId)
> +        self.value = int(value)
> +
> +        Producer.producers[longId] = self
> +        Producer.producerIdList.append(self.longId)
> +        Producer.nProducers += 1
> +
> +    @classmethod
> +    def clearData(cls):
> +        """
> +        Deletes all information read about producers.
> +
> +        Returns nothing.
> +        """
> +
> +        cls.producers.clear()
> +        cls.nProducers = 0
> +        del cls.producerIdList[:]
> +
> +    @classmethod
> +    def getProducerByLongId(cls, longId):
> +        """
> +        Returns a producer given its long id.
> +        If there is no producer with this long id yet, it will be created.
> +        """
> +
> +        if longId not in cls.producers:
> +            cls.producers[longId] = Producer(longId)
> +
> +        return cls.producers[longId]
> +
> +    @classmethod
> +    def getProducerByShortId(cls, shortId):
> +        """
> +        Returns a producer given its short id.
> +        If there is no producer with thi short id yet, IndexError will be thrown.
> +        """
> +
> +        return cls.producers[cls.producerIdList[shortId]]
> +
> +    @classmethod
> +    def exists(cls, longid):
> +        """
> +        Returns if a producer with the given long id exists.
> +        """
> +
> +        return longid in cls.producers
> +
> +    @classmethod
> +    def shortIdToLongId(cls, shortId):
> +        """
> +        Transforms a producer's short id to a long id.
> +
> +        Returns a long id.
> +        Throws an IndexError if the short id does not exist.
> +        """
> +
> +        return cls.producerIdList[shortId]
> +
> +    @classmethod
> +    def longIdToShortId(cls, longId):
> +        """
> +        Transforms a producer's long id to a short id.
> +
> +        Returns a long id.
> +        Throws an KeyError if the long id does not exist.
> +        """
> +        return cls.producers[longId].shortId
> +
> +
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/Producer.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py?view=auto&rev=565392
> ==============================================================================
>     (empty)
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzerengine/__init__.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,71 @@
> +"""
> +Module Application
> +"""
> +import wx
> +from DirectoryPanel import DirectoryPanel
> +from TabbedPanel import TabbedPanel
> +
> +class MainPanel(wx.Panel):
> +    """
> +    Panel contained into the window of the application.
> +    It contains a DirectoryPanel and a TabbedPanel.
> +
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.Panel.__init__(self, parent, -1)
> +
> +        self.tabbedPanel = TabbedPanel(self)
> +
> +        sizer = wx.BoxSizer(wx.VERTICAL)
> +        sizer.Add(DirectoryPanel(self), 0, wx.EXPAND|wx.ALL, 5)
> +        sizer.Add(self.tabbedPanel, 1, wx.EXPAND)
> +        self.SetSizer(sizer)
> +
> +    def logDataUpdated(self):
> +        """
> +        Method to be called when the parsed data has been updated.
> +        The Panel will notify its children components.
> +        """
> +
> +        self.tabbedPanel.logDataUpdated()
> +
> +class MainFrame(wx.Frame):
> +    """
> +    This class represents the window of the application.
> +    It contains a MainPanel object.
> +    We need to add a wx.Panel to a wx.Frame to avoid
> +    graphical problems in Windows.
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.Frame.__init__(self, parent, 100,
> +                          'ActiveMQ Log Analyzer Tool', size=(1024,800))
> +#        ib = wx.IconBundle()
> +#        ib.AddIconFromFile("logparser.ico", wx.BITMAP_TYPE_ANY)
> +#        self.SetIcons(ib)
> +        sizer = wx.BoxSizer(wx.VERTICAL)
> +        sizer.Add(MainPanel(self), 1, wx.EXPAND)
> +        self.SetSizer(sizer)
> +        self.Centre()
> +        self.Show(True)
> +
> +class Application(wx.App):
> +    """
> +    Main class of the application
> +    """
> +
> +    def OnInit(self):
> +        """
> +        To be executed when Application is launched
> +        """
> +        MainFrame(None)
> +        return True
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/Application.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,61 @@
> +"""
> +Module DirectoryPanel
> +"""
> +import wx
> +import os
> +
> +from loganalyzerengine.LogParser import LogParser
> +
> +class DirectoryPanel(wx.Panel):
> +    """
> +    Panel to choose the directory with the log files to be parsed,
> +    and launch the parsing / analyzing process.
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.Panel.__init__(self, parent, -1)
> +        self.mainPanel = parent
> +        self.textctrl = wx.TextCtrl(self, -1, 'C:\logs')
> +
> +        self.lastDirectoryOpen = ''
> +
> +        sizer = wx.BoxSizer(wx.HORIZONTAL)
> +        sizer.Add(wx.StaticText(self, -1, 'Directory'), 0, wx.CENTER|wx.RIGHT, 5)
> +        sizer.Add(self.textctrl, 1, wx.CENTER|wx.RIGHT, 5)
> +        sizer.Add(wx.Button(self, 100 , 'Choose'), 0, wx.CENTER|wx.RIGHT, 5)
> +        sizer.Add(wx.Button(self, 101 , 'Parse'), 0, wx.CENTER)
> +
> +        self.Bind(wx.EVT_BUTTON, self.OnChoose, id=100)
> +        self.Bind(wx.EVT_BUTTON, self.OnParse, id=101)
> +
> +        self.SetSizer(sizer)
> +
> +    def OnChoose(self, event):
> +        """
> +        Action to be executed when the 'Choose' button is pressed.
> +        """
> +
> +        dialog = wx.DirDialog(self, defaultPath=self.lastDirectoryOpen)
> +        if dialog.ShowModal() == wx.ID_OK:
> +            self.textctrl.SetValue(dialog.GetPath())
> +            self.lastDirectoryOpen = dialog.GetPath()
> +        else:
> +            wx.MessageDialog(self, 'Please choose an appropiate directory', style=wx.OK).ShowModal()
> +
> +    def OnParse(self, event):
> +        """
> +        Action to be executed when the 'Parse' button is pressed.
> +        """
> +
> +        path = self.textctrl.GetValue()
> +        if os.path.isdir(path):
> +            LogParser.getInstance().parseDirectory(path)
> +            self.mainPanel.logDataUpdated()
> +            LogParser.deleteInstance()
> +        else:
> +            wx.MessageDialog(self, 'That directory does not exist', style=wx.OK).ShowModal()
> +
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/DirectoryPanel.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,184 @@
> +"""
> +Module IncorrectSequenceList
> +"""
> +import wx
> +from loganalyzerengine.Connection import Connection
> +from loganalyzerengine.LogFile import LogFile
> +
> +def advisoryString(message):
> +    """
> +    Helper method
> +    """
> +
> +    if message.advisory:
> +        return ' (ADVISORY)'
> +    else:
> +        return ''
> +
> +
> +class IncorrectSequenceList(wx.ListCtrl):
> +    """
> +    List of the incorrect events detected after parsing the logs.
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.ListCtrl.__init__(self, parent, -1,
> +                             style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_HRULES|wx.LC_VRULES)
> +
> +        self.incorrectSequencePanel = parent
> +
> +        self.datapresent = False
> +        self.connectionForFilter = None
> +
> +        self.InsertColumn(0, 'Type')
> +        self.InsertColumn(1, 'Connection id / File')
> +        self.InsertColumn(2, 'Message id (prod id | prod seq id)')
> +        self.InsertColumn(3, 'ntimes')
> +        self.InsertColumn(4, 'timestamps')
> +
> +        self.SetColumnWidth(0, 150)
> +        self.SetColumnWidth(1, 250)
> +        self.SetColumnWidth(2, 300)
> +        self.SetColumnWidth(3, 100)
> +        self.SetColumnWidth(4, 300)
> +
> +
> +    def logDataUpdated(self):
> +        """
> +        This method must be called to notify the list that the parsed data
> +        has changed.
> +        """
> +
> +        self.datapresent = True
> +        self.updateList()
> +
> +    def checkConnectionForFilter(self):
> +        """
> +        Returns True if the connection that was inputed by the user
> +        to filter the events is valid.
> +        self.connectionForFilter is a (string, boolean) tuple.
> +        The boolean value is True if the string is a shortId, and False if it is a long id.
> +        """
> +
> +        if self.connectionForFilter is None:
> +            return False
> +
> +        if self.connectionForFilter[1]:
> +            #shortId
> +            return self.connectionForFilter[0].isdigit() and \
> +                   int(self.connectionForFilter[0]) > -1 and \
> +                   int(self.connectionForFilter[0]) < len(Connection.connectionIdList)
> +
> +        else:
> +            #longId
> +            return self.connectionForFilter[0] in Connection.connections
> +
> +    def updateList(self):
> +        """
> +        Updates the display of the list of incorrect events
> +        """
> +
> +        self.DeleteAllItems()
> +        if self.datapresent:
> +            options = self.incorrectSequencePanel.options
> +
> +            row = 0
> +
> +            # we construct a list of connection long ids to be displayed,
> +            # depending on the filter desired
> +            if self.checkConnectionForFilter():
> +                if self.connectionForFilter[1]:
> +                    #shortId
> +                    connectionIds = [Connection.connectionIdList[int(self.connectionForFilter[0])]]
> +                else:
> +                    connectionIds = [self.connectionForFilter[0]]
> +            else:
> +                if self.connectionForFilter is None or self.connectionForFilter[0] == '':
> +                    connectionIds = Connection.connections.keys()
> +                else:
> +                    connectionIds = []
> +
> +            # we display the problems tied to connections
> +            showShortIDs = options['showShortIds']
> +
> +            for longId in connectionIds:
> +
> +                # we display long or short ids depending on the option chosen
> +                connection = Connection.getConnectionByLongId(longId)
> +                errors = connection.getErrors()
> +
> +                if showShortIDs:
> +                    printedConnectionId = connection.shortId
> +                else:
> +                    printedConnectionId = longId
> +
> +                # sent but not received messages
> +                if options['sentButNotReceived']:
> +                    for storedMessage, n, timestamps in errors[0]:
> +                        message = storedMessage[0]
> +                        self.insertRow(row, 'sentButNotReceived' + advisoryString(message), printedConnectionId,
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +                # received but not sent messages
> +                if options['receivedButNotSent']:
> +                    for storedMessage, n, timestamps in errors[1]:
> +                        message = storedMessage[0]
> +                        self.insertRow(row, 'receivedButNotSent' + advisoryString(message), printedConnectionId,
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +                # duplicate sent or received messages through a connection
> +                if options['duplicateInConnection']:
> +                    for storedMessage, n, timestamps in errors[2]:
> +                        message = storedMessage[0]
> +                        self.insertRow(row, 'duplicateSentInConnection' + advisoryString(message), printedConnectionId,
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +                    for storedMessage, n, timestamps in errors[3]:
> +                        message = storedMessage[0]
> +                        self.insertRow(row, 'duplicateReceivedInConnection' + advisoryString(message), printedConnectionId,
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +            # duplicate sent or received messages in the same log file.
> +            # right now they are only shown when the connection filter is not used.
> +            if options['duplicateInFile'] and not self.checkConnectionForFilter() and \
> +            (self.connectionForFilter is None or self.connectionForFilter[0] == ''):
> +                for logfile in LogFile.logfiles:
> +                    errors = logfile.getErrors()
> +
> +                    for message, n, timestamps in errors[0]:
> +                        self.insertRow(row, 'duplicateSentInFile' + advisoryString(message), str(logfile),
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +                    for message, n, timestamps in errors[1]:
> +                        self.insertRow(row, 'duplicateReceivedInFile' + advisoryString(message), str(logfile),
> +                                       message.producer.shortId if showShortIDs else message.producer.longId,
> +                                       message.prodSeqId, n, timestamps, wx.WHITE)
> +                        row += 1
> +
> +    def insertRow(self, rownumber, typeOfError, connectionId, producerId, producerSequenceId, n, timestamps, col):
> +        """
> +        Helper method to insert a row into the list
> +        """
> +
> +        self.InsertStringItem(rownumber, typeOfError)
> +        self.SetStringItem(rownumber, 1, str(connectionId))
> +        self.SetStringItem(rownumber, 2, str(producerId) + ' | ' + str(producerSequenceId))
> +        self.SetStringItem(rownumber, 3, str(n))
> +        self.SetStringItem(rownumber, 4, ' | '.join(timestamps))
> +        self.SetItemBackgroundColour(rownumber, col)
> +
> +
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequenceList.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,135 @@
> +"""
> +Module IncorrectSequencePanel
> +"""
> +import wx
> +from IncorrectSequenceList import IncorrectSequenceList
> +
> +class IncorrectSequencePanel(wx.Panel):
> +    """
> +    This panel contains a list of incorrect events dectected by the parsing,
> +    and many controls to filter which events appear.
> +    Also the user can change if long ids (original ActiveMQConnection id strings, long)
> +    or short ids (a different integer for each connection) is desired.
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.Panel.__init__(self, parent, -1)
> +
> +        self.parent = parent
> +        self.options = {}
> +
> +        self.incorrectSequenceList = IncorrectSequenceList(self)
> +        self.showShortIds = wx.CheckBox(self, 100, 'Show results with short ids')
> +        self.sentButNotReceived = wx.CheckBox(self, 101, 'Sent but not received')
> +        self.receivedButNotSent = wx.CheckBox(self, 102, 'Received but not sent')
> +        self.duplicateInConnection = wx.CheckBox(self, 103, 'Duplicate in connection')
> +        self.duplicateInFile = wx.CheckBox(self, 104, 'Duplicate in log file')
> +        self.connectionText = wx.TextCtrl(self, -1, '')
> +        self.rbshortId = wx.RadioButton(self, -1, style=wx.RB_GROUP, label="Short id")
> +        self.rblongId = wx.RadioButton(self, -1, label="Long id")
> +
> +        self.showShortIds.SetValue(True)
> +        self.sentButNotReceived.SetValue(True)
> +        self.receivedButNotSent.SetValue(True)
> +        self.duplicateInConnection.SetValue(True)
> +        self.duplicateInFile.SetValue(True)
> +
> +        sizer = wx.BoxSizer(wx.VERTICAL)
> +
> +        sizer2 = wx.GridSizer()
> +        sizer2 = wx.GridSizer(2, 2, 5, 5)
> +        sizer2.AddMany([self.sentButNotReceived,
> +                        self.receivedButNotSent,
> +                        self.duplicateInConnection,
> +                        self.duplicateInFile
> +                       ])
> +
> +        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
> +        sizerrb = wx.BoxSizer(wx.VERTICAL)
> +        sizerrb.Add(self.rbshortId, 0, wx.DOWN, 5)
> +        sizerrb.Add(self.rblongId, 0)
> +        sizer3.Add(wx.StaticText(self, -1, 'Filter by connection\n(leave blank to view all)'), 0, wx.CENTER|wx.RIGHT, 5)
> +        sizer3.Add(self.connectionText, 1, wx.CENTER|wx.RIGHT, 5)
> +        sizer3.Add(sizerrb, 0, wx.CENTER|wx.RIGHT, 5)
> +        sizer3.Add(wx.Button(self, 105, 'Filter'), 0, wx.CENTER)
> +
> +        sizer4 = wx.BoxSizer(wx.HORIZONTAL)
> +        sizer4.Add(sizer2, 0, wx.CENTER)
> +        sizer4.Add(sizer3, 1, wx.EXPAND|wx.CENTER|wx.LEFT, 20)
> +
> +        sizer.Add(sizer4, 0, wx.EXPAND|wx.ALL, 5)
> +
> +        sizer5 = wx.BoxSizer(wx.HORIZONTAL)
> +        sizer5.Add(self.showShortIds, 0, wx.RIGHT|wx.CENTER, 5)
> +        sizer5.Add(wx.Button(self, 106, 'Jump to Message Browsing'), 0, wx.CENTER)
> +
> +        sizer.Add(sizer5, 0, wx.ALL, 5)
> +
> +        sizer.Add(self.incorrectSequenceList, 1, wx.EXPAND)
> +
> +        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=100)
> +        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=101)
> +        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=102)
> +        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=103)
> +        self.Bind(wx.EVT_CHECKBOX, self.OptionsChanged, id=104)
> +        self.Bind(wx.EVT_BUTTON, self.OnFilter, id=105)
> +        self.Bind(wx.EVT_BUTTON, self.OnJump, id=106)
> +
> +        self.parseOptions()
> +
> +        self.SetSizer(sizer)
> +
> +    def logDataUpdated(self):
> +        """
> +        This method must be called to notify the panel that the parsed data has been updated.
> +        It will in turn notify the list.
> +        """
> +
> +        self.incorrectSequenceList.logDataUpdated()
> +
> +    def parseOptions(self):
> +        """
> +        Stores the values of the various checkboxes into self.options.
> +        """
> +
> +        self.options['showShortIds'] = self.showShortIds.IsChecked()
> +        self.options['sentButNotReceived'] = self.sentButNotReceived.IsChecked()
> +        self.options['receivedButNotSent'] = self.receivedButNotSent.IsChecked()
> +        self.options['duplicateInConnection'] = self.duplicateInConnection.IsChecked()
> +        self.options['duplicateInFile'] = self.duplicateInFile.IsChecked()
> +
> +    def OptionsChanged(self, event):
> +        """
> +        Action to be executed every time one of the checkboxes is clicked.
> +        It calls parseOptions() and then updates the display of incorrect events.
> +        """
> +
> +        self.parseOptions()
> +        self.incorrectSequenceList.updateList()
> +
> +    def OnFilter(self, event):
> +        """
> +        Action to be executed every time the button 'filter' is pressed.
> +        """
> +
> +        self.incorrectSequenceList.connectionForFilter = (self.connectionText.GetValue(), self.rbshortId.GetValue())
> +        self.OptionsChanged(event)
> +
> +    def OnJump(self, event):
> +        """
> +        Action to be executed when the 'jump' button is pressed.
> +        """
> +
> +        if self.incorrectSequenceList.GetFirstSelected() != -1:
> +            connectionId, messageId = self.incorrectSequenceList.GetItem(self.incorrectSequenceList.GetFirstSelected(), 2).GetText().split(' | ')
> +            self.parent.GetParent().browsingMessagesPanel.textctrl1.SetValue(connectionId)
> +            self.parent.GetParent().browsingMessagesPanel.textctrl2.SetValue(messageId)
> +            self.parent.GetParent().browsingMessagesPanel.rbshortId.SetValue(self.showShortIds.GetValue())
> +            self.parent.GetParent().browsingMessagesPanel.rblongId.SetValue(not self.showShortIds.GetValue())
> +            self.parent.GetParent().browsingMessagesPanel.displayMessageInfo(event)
> +
> +            self.parent.SetSelection(1)
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/IncorrectSequencePanel.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py?view=auto&rev=565392
> ==============================================================================
> --- activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py (added)
> +++ activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py Mon Aug 13 09:03:25 2007
> @@ -0,0 +1,66 @@
> +"""
> +Module MessageTravelPanel
> +"""
> +import wx
> +from MessageTravelText import MessageTravelText
> +
> +class MessageTravelPanel(wx.Panel):
> +    """
> +    The function of this panel is to show the travel history of a message.
> +    This means the connections that the message went through.
> +    """
> +
> +    def __init__(self, parent):
> +        """
> +        Constructor
> +        """
> +
> +        wx.Panel.__init__(self, parent, -1)
> +
> +        self.rbshortId = wx.RadioButton(self, -1, style=wx.RB_GROUP, label="Short id")
> +        self.rblongId = wx.RadioButton(self, -1, label="Long id")
> +        self.textctrl1 = wx.TextCtrl(self, -1, '')
> +        self.textctrl2 = wx.TextCtrl(self, -1, '')
> +        self.chkshowshortId = wx.CheckBox(self, 100, 'Show result with short ids')
> +        self.messageTravelPanel = MessageTravelText(self)
> +
> +        self.chkshowshortId.SetValue(True)
> +
> +        sizerrb = wx.BoxSizer(wx.VERTICAL)
> +        sizerrb.Add(self.rbshortId, 0, wx.DOWN, 5)
> +        sizerrb.Add(self.rblongId, 0)
> +
> +        sizerinput = wx.BoxSizer(wx.HORIZONTAL)
> +        sizerinput.Add(sizerrb, 0, wx.RIGHT, 5)
> +        sizerinput.Add(wx.StaticText(self, -1, 'Producer id'), 0, wx.CENTER|wx.RIGHT, 5)
> +        sizerinput.Add(self.textctrl1, 2, wx.CENTER|wx.RIGHT, 5)
> +        sizerinput.Add(wx.StaticText(self, -1, 'Producer Sequence id'), 0, wx.CENTER|wx.RIGHT, 5)
> +        sizerinput.Add(self.textctrl2, 1, wx.CENTER|wx.RIGHT, 5)
> +        sizerinput.Add(wx.Button(self, 101 , 'Browse'), 0, wx.CENTER)
> +
> +        sizer = wx.BoxSizer(wx.VERTICAL)
> +        sizer.Add(sizerinput, 0, wx.EXPAND|wx.ALL, 5)
> +        sizer.Add(self.chkshowshortId, 0, wx.LEFT|wx.UP, 5)
> +        sizer.Add(self.messageTravelPanel, 1, wx.EXPAND|wx.ALL, 5)
> +
> +        self.Bind(wx.EVT_CHECKBOX, self.displayMessageInfo, id=100)
> +        self.Bind(wx.EVT_BUTTON, self.displayMessageInfo, id=101)
> +
> +        self.SetSizer(sizer)
> +
> +    def displayMessageInfo(self, event):
> +        """
> +        Action to be executed when the 'Browse' button is pushed.
> +        """
> +
> +        self.messageTravelPanel.displayMessageInfo(self.textctrl1.GetValue(),
> +                                                 self.textctrl2.GetValue(),
> +                                                 self.rbshortId.GetValue())
> +
> +    def logDataUpdated(self):
> +        """
> +        This method must be called to notify the panel that the parsed data has been updated.
> +        It will in turn notify the message travel panel.
> +        """
> +
> +        self.messageTravelPanel.logDataUpdated()
> \ No newline at end of file
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.py
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
> URL: http://svn.apache.org/viewvc/activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc?view=auto&rev=565392
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Propchange: activemq/trunk/log_analyzer_tool/loganalyzergui/MessageTravelPanel.pyc
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
>
>
>


-- 
Regards,
Hiram

Blog: http://hiramchirino.com