class MessageBus: """ MessageBus is the heart of the backend messaging system. Almost all communication between components goes through this MessageBus. Components communicate with Messages, which are delivered to MessageHandlers via MessageBus. MessageBus knows which MessageHandlers are interested in which type of Messages. MessageBus is also aware of MessageHandler priorities and this way can serve high priority components first. When MessageHandler is registered to the MessageBus there is also another parameter besides handler itself. Second parameter is a dictionary that defines MessageTypes that registered handler wants to be notified of and also priorities for those message types.""" # This determines number of message types avaialble. In other words, this # variable tells how many variables is defined in MessageType class. NUMBER_OF_MESSAGE_TYPES = len( [k for k, v in vars(MessageType).items() if type(v) is int] ) def __init__(self): """ Create a new MessageBus object. """ # MessageHandlers - index is MessageType and data is a list of # tuples (priority, MessageHandler object) that is sorted by # priorities. #XXX: rockstar - WTF?! Why is there a list comprehension being used # and still only returning an empty list? # pylint: disable-msg=W0612 self.message_handlers = [ [] for i in range(self.NUMBER_OF_MESSAGE_TYPES) ] self.lock = threading.Lock() self.logger = Logger().getLogger('backend.core.MessageBus') def registerMessageHandler(self, message_handler, message_priority_list): """ Register a new MessageHandler to this MessageBus @param message_handler: MessageHandler object @param message_priority_list: Priority list for this MessageHandler """ if isinstance(message_handler, MessageHandler): for key in message_priority_list: rule = (message_priority_list[key], message_handler) self.message_handlers[key].append(rule) self.message_handlers[key].sort() # Keep priority order else: self.logger.critical( "MessageHandler registration failed. Object " + repr(message_handler) +" is invalid type.") raise TypeError("Only MessageHandlers can be registered!") self.logger.debug("MessageHandler '" + str(message_handler) + "' registered to the message bus.") def unregisterMessageHandler(self, message_handler): """ Unregister MessageHandler form this MessageBus. @param message_handler: MessageHandler object that should be removed from bus """ if isinstance(message_handler, MessageHandler): for i in range(self.NUMBER_OF_MESSAGE_TYPES): if len(self.message_handlers[i]) != 0: rules = self.message_handlers[i] for element in rules: if element[1] is message_handler: del element else: raise TypeError("Only MessageHandlers can be unregistered!") self.logger.debug("MessageHandler '" + str(message_handler) + "' unregistered from the message bus.") def notifyMessage(self, message): """ Emit a new Message to this MessageBus. @param message: Message object """ if isinstance(message, Message): self.lock.acquire() # Lock messagebus self.logger.debug("Message bus locked. Message of type '" + str(message.get_type()) + "' is on the bus.") handler_list = self.message_handlers[message.get_type()] for element in handler_list: element[1].handleMessage(message) self.lock.release() # Release messagebus lock else: message = "TypeError occured when message was notified to the bus." self.logger.error(message) exmessage = "Notified message must be instances of 'Message' type" raise TypeError(exmessage)
class LogViewer: """ Implements dialog that allows user to see logged events. This dialog is used to check Entertainer logfiles. It reads all data from selected file and saves rows to self.log_rows. Then it filters unwanted rows away by calling self.filterMessages(). This method adds rows to ListStore, which is the model of TreeView object. Combobox and refresh -button actions read files again Checkbox actions just filter current rows again """ UI_DIR = os.path.join(os.path.dirname(__file__), "uis") # Is this dialog running as a stand alone process __STAND_ALONE = None widgets = None dialog = None log_store = None log_rows = [] def __init__(self, stand_alone): self.logfile_entertainer = Configuration().LOG self.logger = Logger().getLogger('utils.log_viewer') self.__STAND_ALONE = stand_alone try: uifile = os.path.join(self.UI_DIR, "log_dialog.ui") self.builder = gtk.Builder() self.builder.set_translation_domain('entertainer') self.builder.add_from_file(uifile) except RuntimeError: self.logger.critical("Couldn't open ui file: " + uifile) sys.exit(1) callback_dic = { "on_close_log_button_clicked" : self.on_close_log_button_clicked, "on_log_refresh_button_clicked" : self.update_log_rows, "on_checkbutton_debug_toggled" : self.filter_messages, "on_checkbutton_critical_toggled" : self.filter_messages, "on_checkbutton_error_toggled" : self.filter_messages, "on_checkbutton_warning_toggled" : self.filter_messages, "on_checkbutton_info_toggled" : self.filter_messages } self.builder.connect_signals(callback_dic) # Create log treeview treeview = self.builder.get_object("treeview_log") cell_renderer1 = gtk.CellRendererText() cell_renderer2 = gtk.CellRendererText() cell_renderer3 = gtk.CellRendererText() cell_renderer4 = gtk.CellRendererText() column1 = gtk.TreeViewColumn("Date") column1.pack_start(cell_renderer1, True) column1.set_attributes(cell_renderer1, text = 0) column2 = gtk.TreeViewColumn("Time") column2.pack_start(cell_renderer2, True) column2.set_attributes(cell_renderer2, text = 1) column3 = gtk.TreeViewColumn("Type") column3.pack_start(cell_renderer3, True) column3.set_attributes(cell_renderer3, text = 2) column4 = gtk.TreeViewColumn("Message") column4.pack_end(cell_renderer4, True) column4.set_attributes(cell_renderer4, text = 3) treeview.append_column(column1) treeview.append_column(column2) treeview.append_column(column3) treeview.append_column(column4) treeview.set_headers_visible(True) # Set model to view and read data from logfile self.log_store = gtk.ListStore(str, str, str, str) treeview.set_model(self.log_store) self.update_log_rows() # Show Log viewer dialog self.dialog = self.builder.get_object("LogDialog") self.dialog.resize(750, 500) self.dialog.connect("destroy", self.on_close_log_button_clicked) self.dialog.show() def update_log_rows(self, widget=None): """Read logfile and udpate treeview""" self.log_rows[:] = [] try: for line in open(self.logfile_entertainer, 'r'): try: line_table = line.split() message = ' '.join(line_table[3:]) row = line_table[:3] + [message] parsed_row = parse_row(row) self.log_rows.append(parsed_row) except IndexError: print "Cannot parse log line: ", line except IOError: print "Cannot find logfile: ", self.logfile_entertainer # Reverse so that the latest message is at top self.log_rows.reverse() # Filter unwated message types self.filter_messages() def filter_messages(self, widget = None): """Checks which message types should be displayed on treeview""" if self.log_store: self.log_store.clear() debug = self.builder.get_object("checkbutton_debug").get_active() critical = self.builder.get_object("checkbutton_critical").get_active() error = self.builder.get_object("checkbutton_error").get_active() warning = self.builder.get_object("checkbutton_warning").get_active() info = self.builder.get_object("checkbutton_info").get_active() for element in self.log_rows: if element[2] == "DEBUG" and debug: self.log_store.append(element) elif element[2] == "CRITICAL" and critical: self.log_store.append(element) elif element[2] == "ERROR" and error: self.log_store.append(element) elif element[2] == "WARNING" and warning: self.log_store.append(element) elif element[2] == "INFO" and info: self.log_store.append(element) # Signal handlers def on_close_log_button_clicked(self, widget): """ If running as a stand alone process, quit. Otherwise only destroy dialog. """ self.dialog.hide() self.dialog.destroy() if(self.__STAND_ALONE): gtk.main_quit()