MSGLogGUIImpl.py

Go to the documentation of this file.
00001 #!/usr/local/bin/python
00002 #
00003 #                               Copyright 2005
00004 #                                     by
00005 #                        The Board of Trustees of the
00006 #                     Leland Stanford Junior University.
00007 #                            All rights reserved.
00008 #
00009 
00010 __facility__ = "Online"
00011 __abstract__ = "GLAST LAT Message Logger GUI"
00012 __author__   = """A. Kavelaars <AliciaK@SLAC.Stanford.edu>
00013                                SLAC - GLAST LAT I&T/Online"""
00014 __date__     = "2005/07/23 00:08:27"
00015 __updated__  = "$Date: 2006/04/26 20:46:39 $"
00016 __version__  = "$Revision: 1.6 $"
00017 __release__  = "$Name: HEAD $"
00018 __credits__  = "SLAC"
00019 
00020 import LICOS.copyright_SLAC
00021 
00022 
00023 from qt import *
00024 from MSGLogGUI import MSGLogGUI
00025 from select import select
00026 import sys, string, struct, types, cPickle, socket
00027 import logging, logging.handlers, logging.config
00028 logging.raiseExceptions = 1
00029 import threading
00030 import atexit
00031 
00032 #~ #
00033 #~ # Levels
00034 
00035 #~ CRITICAL = 50
00036 #~ FATAL = CRITICAL
00037 #~ ERROR = 40
00038 #~ WARN = 30
00039 #~ INFO = 20
00040 #~ DEBUG = 10
00041 #~ NOTSET = 0
00042 
00043 #~ import RunControlCommon
00044 #~ from RunControlCommon import RunControlCommon
00045 
00046 imageInfo_data = [
00047 "20 18 3 1",
00048 "# c #000080",
00049 "a c #808080",
00050 ". c #ffffff",
00051 ".......######.......",
00052 ".....##########.....",
00053 "....############....",
00054 "...######..######...",
00055 "..#######..#######..",
00056 "..################..",
00057 ".##################.",
00058 ".########..########.",
00059 ".########..########.",
00060 ".########..########.",
00061 ".########..########.",
00062 "..#######..#######a.",
00063 "..#######..#######..",
00064 "..a######..######a..",
00065 "...a############a...",
00066 "....a##########a....",
00067 ".....aa######aa.....",
00068 ".......aaaaaa......."
00069 ]
00070 
00071 imageFatal_data = [
00072 "20 18 19 1",
00073 "p c #004040",
00074 "b c #484242",
00075 "d c #5e4f4f",
00076 "j c #675656",
00077 "m c #685151",
00078 "g c #695555",
00079 "a c #808080",
00080 "h c #cddcdc",
00081 "e c #cedcdc",
00082 "k c #d4e1e1",
00083 "n c #e1eded",
00084 "q c #ebefef",
00085 "i c #ecf6f6",
00086 "f c #edf7f7",
00087 "l c #f1fafa",
00088 "o c #f2f6f6",
00089 "c c #f3fcfc",
00090 "# c #ff0000",
00091 ". c #ffffff",
00092 "......########......",
00093 ".....##########.....",
00094 "....############....",
00095 "...#####....#####...",
00096 "..#####......#####..",
00097 ".#####........#####.",
00098 ".####..aa..aa..####.",
00099 ".####...a..a...####.",
00100 ".####..........####.",
00101 ".#####...aa...#####.",
00102 ".######......######.",
00103 ".a######.aa.######a.",
00104 ".ba#####....#####aa.",
00105 ".cda####....####aae.",
00106 "..fga##########aah..",
00107 "...ija########aak...",
00108 "....lmaaaaaaaaan....",
00109 ".....oppppppppq....."
00110 ]
00111 
00112 imageWarn_data = [
00113 "20 18 4 1",
00114 "a c #004040",
00115 "b c #808080",
00116 "# c #ffff00",
00117 ". c #ffffff",
00118 ".........##.........",
00119 "........####........",
00120 "........####........",
00121 ".......######.......",
00122 ".......##aa##.......",
00123 "......###aa###......",
00124 "......###aa###......",
00125 ".....####aa####.....",
00126 ".....####aa####.....",
00127 "....#####aa#####....",
00128 "....#####aa#####....",
00129 "...######aa######...",
00130 "...##############...",
00131 "..################..",
00132 "..#######aa#######..",
00133 ".########aa########.",
00134 ".##################.",
00135 "..bbbbbbbbbbbbbbbbb."
00136 ]
00137 
00138 imageError_data = [
00139 "20 18 3 1",
00140 "a c #808080",
00141 "# c #ff0000",
00142 ". c #ffffff",
00143 ".......######.......",
00144 ".....##########.....",
00145 "....############....",
00146 "...##############...",
00147 "..###..#####..####..",
00148 "..###...###...####..",
00149 ".#####...#...######.",
00150 ".######.....#######.",
00151 ".#######...########.",
00152 ".######.....#######.",
00153 ".#####...#...######.",
00154 ".a###...###...####a.",
00155 "..###..#####..####..",
00156 "..a##############a..",
00157 "...a############a...",
00158 "....a##########a....",
00159 ".....aa######aa.....",
00160 ".......aaaaaa......."
00161 ]
00162 
00163 imageNotset_data = [
00164 "20 18 19 1",
00165 "p c #004040",
00166 "# c #008000",
00167 "b c #484242",
00168 "d c #5e4f4f",
00169 "j c #675656",
00170 "m c #685151",
00171 "g c #695555",
00172 "a c #808080",
00173 "h c #cddcdc",
00174 "e c #cedcdc",
00175 "k c #d4e1e1",
00176 "n c #e1eded",
00177 "q c #ebefef",
00178 "i c #ecf6f6",
00179 "f c #edf7f7",
00180 "l c #f1fafa",
00181 "o c #f2f6f6",
00182 "c c #f3fcfc",
00183 ". c #ffffff",
00184 "......########......",
00185 ".....##########.....",
00186 "....#####..#####....",
00187 "...######..######...",
00188 "..#######..#######..",
00189 ".########..########.",
00190 ".########..########.",
00191 ".########..########.",
00192 ".########..########.",
00193 ".########..########.",
00194 ".##################.",
00195 ".a################a.",
00196 ".ba######..######aa.",
00197 ".cda#####..#####aae.",
00198 "..fga##########aah..",
00199 "...ija########aak...",
00200 "....lmaaaaaaaaan....",
00201 ".....oppppppppq....."
00202 ]
00203 
00204 imageDebug_data = [
00205 "20 18 19 1",
00206 "p c #004040",
00207 "b c #484242",
00208 "d c #5e4f4f",
00209 "j c #675656",
00210 "m c #685151",
00211 "g c #695555",
00212 "a c #808080",
00213 "# c #c0c0c0",
00214 "h c #cddcdc",
00215 "e c #cedcdc",
00216 "k c #d4e1e1",
00217 "n c #e1eded",
00218 "q c #ebefef",
00219 "i c #ecf6f6",
00220 "f c #edf7f7",
00221 "l c #f1fafa",
00222 "o c #f2f6f6",
00223 "c c #f3fcfc",
00224 ". c #ffffff",
00225 "......########......",
00226 ".....##########.....",
00227 "....#####..#####....",
00228 "...######..######...",
00229 "..################..",
00230 ".##################.",
00231 ".########..########.",
00232 ".########..########.",
00233 ".########..########.",
00234 ".########..########.",
00235 ".########..########.",
00236 ".a#######..#######a.",
00237 ".ba######..######aa.",
00238 ".cda#####..#####aae.",
00239 "..fga##########aah..",
00240 "...ija########aak...",
00241 "....lmaaaaaaaaan....",
00242 ".....oppppppppq....."
00243 ]
00244 
00245 #~##
00246 from SocketServer import ThreadingTCPServer, StreamRequestHandler
00247 import errno
00248 import select
00249 
00250 
00251 MAX_ENTRIES    = 9000
00252 DELETE_ENTRIES = 100
00253 
00254 class LogRecordStreamHandler(StreamRequestHandler):
00255   """!\brief Handler for a streaming logging request.
00256 
00257   It basically logs the record
00258   using whatever logging policy is configured locally.
00259 
00260   """
00261 
00262   def handle(self):
00263     """!\brief Handle multiple requests.
00264 
00265     Handle multiple requests - each expected to be a 4-byte length,
00266     followed by the LogRecord in pickle format. Logs the record
00267     according to whatever policy is configured locally.
00268 
00269     """
00270     while 1:
00271       try:
00272         chunk = self.connection.recv(4)
00273         if len(chunk) < 4:
00274           break
00275         slen = struct.unpack(">L", chunk)[0]
00276         #print slen
00277         chunk = self.connection.recv(slen)
00278         while len(chunk) < slen:
00279           chunk = chunk + self.connection.recv(slen - len(chunk))
00280         obj = self.unPickle(chunk)
00281         record = logging.makeLogRecord(obj)
00282         #record = logging.LogRecord(None, None, "", 0, "", (), None)
00283         #record.__dict__.update(obj)
00284         self.handleLogRecord(record)
00285       except socket.error, e:
00286         if type(e.args) != types.TupleType:
00287           raise e
00288         else:
00289           errcode = e.args[0]
00290           if errcode != errno.ECONNRESET:
00291             raise e
00292           break
00293 
00294   def unPickle(self, data):
00295     """!\brief Unpickle incoming log packet
00296 
00297     \param data Log packet
00298 
00299     \return Unpickled log packet
00300     """
00301     return cPickle.loads(data)
00302 
00303   def handleLogRecord(self, record):
00304     """!\brief Process the log record.
00305 
00306     Send the log record to the GUI class for processing.
00307 
00308     \param record Log record
00309 
00310     """
00311     #if a name is specified, we use the named logger rather than the one
00312     #implied by the record. This is so test harnesses don't get into
00313     #endless loops (particularly log_test.py, which has this code and the
00314     #client code in the same Python instance)
00315     if self.server.logname is not None:
00316       name = self.server.logname
00317     else:
00318       name = record.name
00319     logger = logging.getLogger(name)
00320     #logger.handle(record)
00321     #print logger.handlers[0].format(record)
00322 
00323     #~ self.__actualData = logger.handlers[0].format(record)
00324 
00325     self.server.gui.appendLogData(logger.handlers[0].format(record))
00326 
00327 
00328 class MSGLogSocketReceiver(ThreadingTCPServer):
00329   """!\brief Socket server class for receiving log packets.
00330 
00331   """
00332   allow_reuse_address = 1
00333 
00334   def __init__(self, gui, host='', port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
00335       handler=LogRecordStreamHandler):
00336     """!\brief MSGLogSocketReceiver constructor.
00337 
00338     \param gui     Message logger GUI
00339     \param host    Host to listen to (If blank it receives data from any host)
00340     \param port    Logging port
00341     \param handler Handler class
00342     """
00343     ThreadingTCPServer.__init__(self, (host, port), handler)
00344     self.__abort = 0
00345     self.timeout = 1
00346     self.logname = None
00347     self.gui = gui
00348     self.handler = handler
00349 
00350   def abort(self):
00351     """!\brief Stop listening for logs
00352 
00353     """
00354     self.__abort = 1
00355 
00356   def serve_until_stopped(self):
00357     """!\brief Main listen loop
00358 
00359     """
00360     while not self.__abort:
00361       rd, wr, ex = select.select([self.socket.fileno()],
00362                                  [], [],
00363                                  self.timeout)
00364       if rd:
00365         self.handle_request()
00366 
00367 class MSGLogGUIImpl(MSGLogGUI):
00368   """!\brief Message Logger GUI
00369 
00370   """
00371   def __init__(self, port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
00372                updateInterval=100, parent = None,name = None,fl = 0):
00373     """!\brief MSGLogGUIImpl constructor
00374 
00375     \param port           Logging port
00376     \param updateInterval The interval the the GUI will check for new log entries
00377     \param parent         Parent GUI
00378     \param name           Name
00379     \param fl             Flags
00380 
00381     """
00382     MSGLogGUI.__init__(self,parent,name,fl)
00383     #self.setCentralWidget( self.Logger )
00384     self.__secure = 0
00385     self.__timer = QTimer(self)
00386     QObject.connect(self.__timer, SIGNAL("timeout()"), self.addLogDataToView)
00387     self.__updateInterval = updateInterval
00388     self.__timer.start(self.__updateInterval)
00389     self.__port = port
00390     self.__level = 0
00391     self.__filename = None
00392     self.printer = QPrinter()
00393     self.filename = QString.null
00394     self.tcpserver = None
00395     self.__logname = "MSGLogger"
00396     self.__logData = []
00397     self.__logList = []
00398     self.__count = 0
00399     self.__previousMSG = ["","","",""]
00400     self.__previousMSGcut = ["",""]
00401 
00402     self.imageFatal = QPixmap(imageFatal_data)
00403     self.imageError = QPixmap(imageError_data)
00404     self.imageWarn = QPixmap(imageWarn_data)
00405     self.imageInfo = QPixmap(imageInfo_data)
00406     self.imageDebug = QPixmap(imageDebug_data)
00407     self.imageNotset = QPixmap(imageNotset_data)
00408 
00409     self.connect(self.filterbyCritical,SIGNAL("activated()"),self.levelCritical)
00410     self.connect(self.filterbyFatal,SIGNAL("activated()"),self.levelFatal)
00411     self.connect(self.filterbyError,SIGNAL("activated()"),self.levelError)
00412     self.connect(self.filterbyWarn,SIGNAL("activated()"),self.levelWarn)
00413     self.connect(self.filterbyInfo,SIGNAL("activated()"),self.levelInfo)
00414     self.connect(self.filterbyDebug,SIGNAL("activated()"),self.levelDebug)
00415     self.connect(self.filterbyNotset,SIGNAL("activated()"),self.levelNotset)
00416     self.connect(self.noFilter,SIGNAL("activated()"),self.levelNoFilter)
00417 
00418     #~ self.connect(self.Logger,SIGNAL("currentChanged(QListViewItem*)"),self.preventSaturation)
00419     self.connect(self.Logger,SIGNAL("currentChanged(QListViewItem*)"),self.showEntries)
00420     #self.connect(self.Logger, SIGNAL('clicked(QListViewItem*)'), self.preventCheck)
00421     self.connect(self.RunningLogButton,SIGNAL("clicked()"),self.switchToRunningLog)
00422     self.connect(self.FileLogButton,SIGNAL("clicked()"),self.fileOpen)
00423 
00424     self.contextMenu = QPopupMenu( self )
00425     self.contextMenu.insertItem( "&Copy", self.copyToClipboard, Qt.CTRL+Qt.Key_C)
00426     self.contextMenu.insertItem( "Copy Whole &Row", self.copyRowToClipboard, Qt.CTRL+Qt.Key_R)
00427     self.clip = QApplication.clipboard()
00428 
00429     QObject.connect(self.Logger,
00430                     SIGNAL("contextMenuRequested(QListViewItem*,const QPoint&,int)"),
00431                     self.contextMenuShow
00432                    )
00433 
00434     #atexit.register(logging.shutdown)
00435     atexit.register(self.__shutdown)
00436 
00437     self.__hdlr = logging.StreamHandler()
00438     fmt = logging.Formatter("%(asctime)s %(filename)s:%(lineno)d %(levelname)-5s - %(message)s")
00439     self.__hdlr.setFormatter(fmt)
00440     logger = logging.getLogger(self.__logname)
00441     logger.addHandler(self.__hdlr)
00442     #logger.propagate = 0
00443 
00444     self.Logger.setColumnAlignment(0, Qt.AlignLeft | Qt.AlignVCenter)
00445     self.Logger.header().setMovingEnabled(0)
00446 
00447     self.Logger.setSorting(-1,1)
00448 
00449     #self.Logger.setColumnWidth(0,0)
00450     #~ self.Logger.setColumnWidth(1,40)
00451     #~ self.Logger.setColumnWidth(2,20)
00452     #~ self.Logger.setColumnWidth(3,80)
00453     #~ self.Logger.setColumnWidth(4,30)
00454 
00455     #~ self.noFilter.setOn(1)
00456     logging.addLevelName(60, 'ALERT')
00457     logging.ALERT = 60
00458 
00459   def preventSaturation(self):
00460     """!\brief Make sure we don't exceed MAX_ENTRIES.
00461 
00462     """
00463     if self.Logger.childCount() >= MAX_ENTRIES:
00464       #print "too many entries"
00465       self.__timer.stop()
00466       item = self.Logger.firstChild()
00467       count = 0
00468       while (count < DELETE_ENTRIES):
00469         if QString.compare(item.text(0),'CRITICAL') != 0 and QString.compare(item.text(0),'FATAL') != 0 :
00470           count += 1
00471           if count >= self.Logger.childCount(): break
00472           saveItem = item.nextSibling()
00473           self.Logger.takeItem(item)
00474           item = saveItem
00475         else:
00476           item = item.nextSibling()
00477 
00478         #~ item = item.nextSibling()
00479       self.__timer.start(self.__updateInterval)
00480 
00481   def showEntries(self):
00482     """!\brief Show number of entries in status bar.
00483 
00484     """
00485     self.statusBar().message('Number of entries: ' + str(self.Logger.childCount()))
00486 
00487   def preventCheck(self):
00488     """!\brief Ask user for acknowledgment for critical and fatal log entries.
00489 
00490     """
00491     item = self.Logger.currentItem()
00492     if item is not None:
00493       if item.isOn():
00494         if QString.compare(item.text(0),'CRITICAL') == 0 or QString.compare(item.text(0),'FATAL') == 0 :
00495           self.statusBar().message('CRITICAL or FATAL error: Uncheck to Acknowledge',2000)
00496         else:
00497           self.statusBar().message('CRITICAL and FATAL errors check boxes ONLY are enabled to be acknowledged',2500)
00498           item.setOn(0)
00499 
00500   def appendLogData(self, data):
00501     """!\brief Append the log to the buffer.
00502 
00503     \param data Log data
00504 
00505     """
00506     self.__logData.append(data)
00507 #    if len(self.__logList) > 10000:
00508 #      rc = QMessageBox.information(self,'GLAT Online Message Logger',
00509 #                  'The Active Logger has reached the maximum of 10000 entries and will now close. Would you like to keep listening in a new log?',
00510 #                  'Yes','No')
00511 #      if rc == 0:
00512 #        # Fill in here what to do
00513 #        e.ignore()
00514 #      else:
00515 #        e.accept()
00516 #    else:
00517 #      self.__logList.append(data)
00518 
00519   def switchToRunningLog(self):
00520     """!\brief Switch from a file based or static view to running log view.
00521 
00522     """
00523     self.LogType.setText("Active Run Control Log")
00524     self.Logger.clear()
00525     #~ print "Data: ", self.__logData
00526     self.addLogDataToView()
00527     if not self.runTCPThread.isAlive():
00528       self.startListenerThread()
00529 
00530     #~ for data in self.__logData:
00531 
00532 
00533   def abortListenerThread(self):
00534     """!\brief Abort the listener thread before loading a file
00535 
00536     """
00537     if self.runTCPThread.isAlive():
00538       self.tcpserver.abort()
00539       self.runTCPThread.join()
00540 
00541 
00542   def startListenerThread(self):
00543     """!\brief Start the listener thread.
00544 
00545     """
00546     self.Logger.clear()
00547     self.LogType.setText("Active Run Control Log")
00548     self.LogType.setAlignment(QLineEdit.AlignLeft)
00549 
00550     self.tcpserver = MSGLogSocketReceiver(self, host='', port=self.__port)
00551     self.tcpserver.logname = self.__logname
00552     self.runTCPThread = threading.Thread(target=self.runTCP, name=self.__logname, args=(self.tcpserver,))
00553     self.runTCPThread.start()
00554 
00555 
00556   def runTCP(self, tcpserver):
00557     """!\brief Start the main listen loop.
00558 
00559     \param tcpserver MSGLogSocketReceiver instance
00560 
00561     """
00562     try:
00563       tcpserver.serve_until_stopped()
00564     finally:
00565       tcpserver.server_close()
00566 
00567 
00568   def clearLevels(self):
00569     """!\brief Clear filter levels.
00570 
00571     """
00572     self.filterbyCritical.setOn(0)
00573     self.filterbyError.setOn(0)
00574     self.filterbyInfo.setOn(0)
00575     self.filterbyDebug.setOn(0)
00576     self.filterbyNotset.setOn(0)
00577     self.filterbyFatal.setOn(0)
00578     self.filterbyWarn.setOn(0)
00579     self.noFilter.setOn(0)
00580 
00581   def levelCritical(self):
00582     """!\brief Filter by critical level
00583 
00584     """
00585     self.clearLevels()
00586     self.filterbyCritical.setOn(1)
00587     self.__level = logging.CRITICAL
00588     #~ for i in range(self.Logger.childCount()-1):
00589     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00590       self.switchToRunningLog()
00591     else:
00592       self.load( )
00593 
00594   def levelFatal(self):
00595     """!\brief Filter by fatal level
00596 
00597     """
00598     self.clearLevels()
00599     self.filterbyFatal.setOn(1)
00600     self.__level = logging.CRITICAL
00601     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00602       self.switchToRunningLog()
00603     else:
00604       self.load( )
00605 
00606   def levelError(self):
00607     """!\brief Filter by error level
00608 
00609     """
00610     self.clearLevels()
00611     self.filterbyError.setOn(1)
00612     self.__level = logging.ERROR
00613     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00614       self.switchToRunningLog()
00615     else:
00616       self.load( )
00617 
00618   def levelWarn(self):
00619     """!\brief Filter by warning level
00620 
00621     """
00622     self.clearLevels()
00623     self.filterbyWarn.setOn(1)
00624     self.__level = logging.WARN
00625     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00626       self.switchToRunningLog()
00627     else:
00628       self.load( )
00629 
00630   def levelInfo(self):
00631     """!\brief Filter by info level
00632 
00633     """
00634     self.clearLevels()
00635     self.filterbyInfo.setOn(1)
00636     self.__level = logging.INFO
00637     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00638       self.switchToRunningLog()
00639     else:
00640       self.load( )
00641 
00642   def levelDebug(self):
00643     """!\brief Filter by debug level
00644 
00645     """
00646     self.clearLevels()
00647     self.filterbyDebug.setOn(1)
00648     self.__level = logging.DEBUG
00649     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00650       self.switchToRunningLog()
00651     else:
00652       self.load( )
00653 
00654   def levelNotset(self):
00655     """!\brief Filter by notset level
00656 
00657     """
00658     self.clearLevels()
00659     self.filterbyNotset.setOn(1)
00660     self.__level = logging.NOTSET
00661     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00662       self.switchToRunningLog()
00663     else:
00664       self.load(  )
00665 
00666   def levelNoFilter(self):
00667     """!\brief Clear filter
00668 
00669     """
00670     self.clearLevels()
00671     self.noFilter.setOn(1)
00672     self.__level = logging.NOTSET
00673     if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00674       #~ self.addLogDataToView()
00675       self.switchToRunningLog()
00676     else:
00677       self.load(  )
00678 
00679   def setListViewItem(self, data):
00680     """!\brief Parse and convert the message log data to a listview item
00681 
00682     \param data Message log data
00683     """
00684     #~ imageFatal = QPixmap(imageFatal_data)
00685     #~ imageError = QPixmap(imageError_data)
00686     #~ imageWarn = QPixmap(imageWarn_data)
00687     #~ imageInfo = QPixmap(imageInfo_data)
00688     #~ imageDebug = QPixmap(imageDebug_data)
00689     #~ imageNotset = QPixmap(imageNotset_data)
00690 
00691     level = self.__level
00692 
00693     p = data.rstrip()
00694 
00695     s = string.splitfields(p)
00696     temps = string.splitfields(p)
00697     r = string.splitfields(p, ' - ',3)
00698 
00699     #Corrects the fact that FATAL is not included in the defs of
00700     # __init__.py for logging in python22
00701 
00702     if temps[3] == 'FATAL':
00703       temps[3] = 'CRITICAL'
00704 
00705     if logging._levelNames[temps[3]] >= level:
00706       if s[2] == self.__previousMSG[2] and s[3] == self.__previousMSG[3] \
00707           and r[1] == self.__previousMSGcut:
00708         #print s[2], s[3], r[1], self.__count
00709         self.__count += 1
00710 
00711       else:
00712         if self.__count >= 3:
00713           messageItem = QListViewItem( self.Logger,self.Logger.lastItem())
00714 
00715           messageItem.setText( 0, self.__previousMSG[3])
00716           messageItem.setText( 2, self.__previousMSG[0])
00717           messageItem.setText( 3, self.__previousMSG[1])
00718           messageItem.setText( 4, self.__previousMSG[2])
00719           #~ for i in range (0, 4):
00720             #~ messageItem.setText( i, self.__previousMSG[i])
00721           self.__countMSG = "The previous message was repeated " + str(self.__count) + " time(s)."
00722           messageItem.setText(1, self.__countMSG)
00723 
00724           if self.__previousMSG[3] == 'CRITICAL' or \
00725              self.__previousMSG[3] == 'FATAL'    or \
00726              self.__previousMSG[3] == 'ALERT':
00727             messageItem.setPixmap(0, self.imageFatal)
00728             messageItem.setOn(1)
00729 
00730           elif self.__previousMSG[3] == 'ERROR':
00731             messageItem.setPixmap(0, self.imageError)
00732 
00733           elif self.__previousMSG[3] == 'WARNING':
00734             messageItem.setPixmap(0, self.imageWarn)
00735 
00736           elif self.__previousMSG[3] == 'INFO':
00737             messageItem.setPixmap(0, self.imageInfo)
00738 
00739           elif self.__previousMSG[3] == 'DEBUG':
00740             messageItem.setPixmap(0, self.imageDebug)
00741 
00742           elif self.__previousMSG[3] == 'NOTSET':
00743             messageItem.setPixmap(0, self.imageNotset)
00744           self.__count = 0
00745 
00746         item = QListViewItem( self.Logger, self.Logger.lastItem())
00747 
00748         item.setText( 0, s[3])
00749         item.setText( 2, s[0])
00750         item.setText( 3, s[1])
00751         item.setText( 4, s[2])
00752         #~ for i in range (0, 4):
00753           #~ item
00754           #~ item.setText( i, s[i])
00755         item.setText(1, r[1])
00756         if r[1].find('\n') != -1:
00757           item.setMultiLinesEnabled(1)
00758 
00759         if s[3]   == 'ALERT':
00760           item.setPixmap(0, self.imageFatal)
00761           item.setOn(1)
00762           self.handleAlert(s)
00763 
00764         elif s[3] == 'CRITICAL' or s[3] == 'FATAL':
00765           item.setPixmap(0, self.imageFatal)
00766           item.setOn(1)
00767 
00768         elif s[3] == 'ERROR':
00769           item.setPixmap(0, self.imageError)
00770 
00771         elif s[3] == 'WARNING':
00772           item.setPixmap(0, self.imageWarn)
00773 
00774         elif s[3] == 'INFO':
00775           item.setPixmap(0, self.imageInfo)
00776 
00777         elif s[3] == 'DEBUG':
00778           item.setPixmap(0, self.imageDebug)
00779 
00780         elif s[3] == 'NOTSET':
00781           item.setPixmap(1, self.imageNotset)
00782 
00783         self.__previousMSG = s
00784         self.__previousMSGcut = r[1]
00785 
00786       self.preventSaturation()
00787 
00788   def handleAlert(self, s):
00789     """!\brief handleAlert
00790 
00791     \param s
00792     """
00793     pass
00794     # print "handleAlert", s
00795 
00796   def addLogDataToView(self):
00797     """!\brief Add the log to the listview
00798 
00799     """
00800   #~ list = []
00801   #~ list.append(data)
00802     self.Logger.blockSignals(1)
00803     while len(self.__logData) > 0:
00804       data = self.__logData.pop(0)
00805       self.setListViewItem(data)
00806 
00807     vScroll = self.Logger.verticalScrollBar()
00808     #~ print vScroll.value(), vScroll.maxValue()
00809     if not self.PauseLogButton.isOn() and not vScroll.draggingSlider() :
00810       vScroll.setValue(vScroll.maxValue())
00811 
00812     self.Logger.blockSignals(0)
00813     self.showEntries()
00814 
00815   #~ def switchToRunningLog(self):
00816     #~ self.Logger.clear()
00817     #~ for data in self.__logList:
00818       #~ self.setListViewItem(data)
00819 
00820   def load( self ):
00821     """!\brief Load a message log file into the logger
00822 
00823     """
00824     if self.tcpserver is not None:
00825       self.abortListenerThread()
00826     self.Logger.clear()
00827 
00828     f = file( str(self.__filename), 'r' )
00829 
00830     #~ if not f.open( IO_ReadOnly ):
00831         #~ return
00832 
00833     #self.__filename = filename
00834     #~ t = QTextStream( f )
00835 
00836     #~ self.noFilter.setOn(1)
00837     multi_line = 0
00838     while 1:
00839       data = f.readline()
00840       data = data[:len(data)-1]
00841       if data == "":
00842         break
00843       if multi_line == 0:
00844         (data1, data2) = data.split(" - ",1)
00845         if data2.startswith("<//") > 0 and multi_line == 0:
00846           datax = data1 + " - " + data2[3:]
00847           multi_line = 1
00848           continue
00849       if multi_line:
00850         if data.endswith("//>"):
00851           datax += "\n" + data[:-3]
00852           multi_line = 0
00853         else:
00854           datax += "\n" + data
00855           continue
00856       else:
00857         datax = data
00858       self.setListViewItem(datax)
00859 
00860     f.close()
00861 
00862   def filePrint(self):
00863     """!\brief Print the message log to the printer
00864 
00865     """
00866     Margin = 50
00867     pageNo = 1
00868     column = [0, 50, 110, 180, 260, 400]#, 325] # Magic numbers
00869 
00870     # If there are no items, don't try to print
00871     if not self.Logger.firstChild():
00872       return
00873 
00874     if self.printer.setup(self):
00875       self.statusBar().message('Printing...')
00876 
00877       p = QPainter()
00878       p.begin(self.printer)
00879       p.setFont(self.Logger.font())
00880       yPos = 0
00881       fm = p.fontMetrics()
00882       metrics = QPaintDeviceMetrics(self.printer)
00883 
00884       if QString.compare(self.LogType.text(), "Active Run Control Log") == 0 :
00885         header = "Message Logger Source: Active Run Control Log"
00886       else:
00887         header = "Message Logger Source: " + str(self.__filename)
00888 
00889       page = "Page: 1"
00890       p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, header)
00891       yPos = yPos + fm.lineSpacing()
00892       p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, page)
00893       yPos = yPos + 2*fm.lineSpacing()
00894 
00895       columnHeader = ['Severity','Message','Date','Time','Source']
00896 
00897       for i in range (0,6):
00898           p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00899                     Qt.ExpandTabs | Qt.DontClip, columnHeader[i])
00900       yPos = yPos + fm.lineSpacing()
00901 
00902       item = self.Logger.firstChild()
00903       for j in range(self.Logger.childCount()):
00904         if Margin + yPos > metrics.height() - Margin:
00905           pageNo = pageNo + 1
00906           page = "Page: " + str(pageNo)
00907           self.statusBar().message('Printing (page %d)...' % (pageNo))
00908           self.printer.newPage()
00909           yPos = 0
00910           p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, header)
00911           yPos = yPos + fm.lineSpacing()
00912           p.drawText(Margin,Margin + yPos,metrics.width(),fm.lineSpacing(),Qt.ExpandTabs | Qt.DontClip, page)
00913           yPos = yPos + 2*fm.lineSpacing()
00914 
00915           for i in range (0,6):
00916             p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00917                       Qt.ExpandTabs | Qt.DontClip, columnHeader[i])
00918           yPos = yPos + fm.lineSpacing()
00919 
00920         for i in range (0,6):
00921           p.drawText(column[i],Margin + yPos,metrics.width(),fm.lineSpacing(),
00922                     Qt.ExpandTabs | Qt.DontClip,item.text(i))
00923         yPos = yPos + fm.lineSpacing()
00924         item = item.nextSibling()
00925 
00926       p.end()
00927       self.statusBar().message('Printing completed',2000)
00928     else:
00929       self.statusBar().message('Printing aborted',2000)
00930 
00931   def Help(self):
00932     """!\brief Help
00933 
00934     """
00935     pass
00936 
00937   def fileNew(self):
00938     """!\brief fileNew
00939 
00940     """
00941     print "MSGLogGUIImpl.fileNew(): Not implemented yet"
00942 
00943   def fileOpen(self):
00944     """!\brief Bring up a file open dialog for log file selection
00945 
00946     """
00947     fn = QFileDialog.getOpenFileName( QString.null, "(*.log)", self, "Log file dialog",
00948                                             "Choose a Log File" )
00949     if not fn.isEmpty():
00950       self.__filename = fn
00951       self.LogType.setText(str(self.__filename))
00952       self.LogType.setAlignment(QLineEdit.AlignRight)
00953       self.load( )
00954 
00955   def fileSave(self):
00956     """!\brief Save log file
00957 
00958     """
00959     if self.__filename.isEmpty():
00960       self.fileSaveAs()
00961       return
00962 
00963     self.Logger.save( self.__filename )
00964 
00965   def fileSaveAs(self):
00966     """!\brief Save log file under a name
00967 
00968     """
00969     fn = QFileDialog.getSaveFileName( QString.null, QString.null, self )
00970     if not fn.isEmpty():
00971       self.__filename = fn
00972       self.fileSave()
00973 
00974   def fileExit(self):
00975     """!\brief Close the GUI
00976 
00977     """
00978     self.close()
00979 
00980   def closeEvent(self, e):
00981     """!\brief Handle exit
00982 
00983     """
00984     if self.__secure:
00985       e.ignore()
00986       return
00987 #    if self.Logger.childCount() == 0:
00988 #      e.accept()
00989 #    item = self.Logger.firstChild()
00990 #    for i in range(self.Logger.childCount()-1):
00991 #      if item.isOn() :#and item.text(3) == "CRITICAL":# or item.text(3) == 'FATAL':
00992 #        rc = QMessageBox.information(self,'GLAT Online Message Logger',
00993 #                  'Please acknowledge all CRITICAL and FATAL errors before exit by unchecking the box at the beginning of the entry',
00994 #                  'OK','Exit Anyway')
00995 #        if rc == 0:
00996 #          e.ignore()
00997 #          break
00998 #        else:
00999 #          e.accept()
01000 #          break
01001 
01002 #      item = item.nextSibling()
01003     e.accept()
01004 
01005   def __shutdown(self):
01006     """!\brief Shutdown the listener thread
01007 
01008     """
01009     self.abortListenerThread()
01010 
01011   def setSecure(self, secure):
01012     """!\brief Set the secure flag
01013 
01014     \param secure Secure flag
01015     """
01016     self.__secure = secure
01017 
01018   def contextMenuShow(self, item, point, column):
01019     """!\brief Bring up the context menu on right mouse click.
01020 
01021     \param item   Listview item
01022     \param point  Position where the mouse was clicked
01023     \param column Listview column
01024     """
01025     self.selectedItem = item
01026     self.contextMenu.exec_loop(point)
01027 
01028   def copyToClipboard(self):
01029     """!\brief Copy the item value to the clipboard.
01030 
01031     """
01032     if self.Logger.selectedItem() is not None:
01033       self.clip.setText(self.Logger.selectedItem().text(1))
01034 
01035   def copyRowToClipboard(self):
01036     """!\brief Copy the item value to the clipboard.
01037 
01038     """
01039     if self.Logger.selectedItem() is not None:
01040       selItem = self.Logger.selectedItem()
01041       text = str(selItem.text(0)) + ' ' + str(selItem.text(1)) + ' ' + \
01042              str(selItem.text(2)) + ' ' + str(selItem.text(3)) + ' ' + \
01043              str(selItem.text(4))
01044       self.clip.setText(text)
01045 
01046 if __name__ == "__main__":
01047   import logging.handlers
01048   from LICOS.util.gOptions import Options
01049   def usage(msg):
01050     print """
01051   Error %s
01052   Usage:  python MSGLogGUIImpl.py [--port <portno>] (default: %d)
01053   """ % (msg, logging.handlers.DEFAULT_TCP_LOGGING_PORT)
01054 
01055   options = Options([],['port'],[])
01056   try:
01057     options.parse()
01058   except Exception, msg:
01059     usage(msg)
01060     sys.exit()
01061 
01062   a = QApplication(sys.argv)
01063   QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
01064   if options.port is None:
01065     port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
01066   else:
01067     port = int(options.port)
01068   w = MSGLogGUIImpl(port)
01069   w.startListenerThread()
01070   a.setMainWidget(w)
01071   w.show()
01072   a.exec_loop()

Generated on Thu Apr 27 20:52:42 2006 for LICOS L02-01-00 by doxygen 1.4.6-NO