2010-07-08 20:01:03 +02:00
|
|
|
#!/usr/bin/python
|
2009-12-05 16:54:49 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2010-07-04 03:05:16 +02:00
|
|
|
#Copyright 2008-2010 Carl Gherardi
|
2009-12-05 16:54:49 +01:00
|
|
|
#This program is free software: you can redistribute it and/or modify
|
|
|
|
#it under the terms of the GNU Affero General Public License as published by
|
|
|
|
#the Free Software Foundation, version 3 of the License.
|
|
|
|
#
|
|
|
|
#This program is distributed in the hope that it will be useful,
|
|
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
#GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
#You should have received a copy of the GNU Affero General Public License
|
|
|
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-07-04 03:05:16 +02:00
|
|
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-09 22:58:56 +01:00
|
|
|
import os
|
|
|
|
import Queue
|
2009-12-05 16:54:49 +01:00
|
|
|
|
|
|
|
import pygtk
|
|
|
|
pygtk.require('2.0')
|
|
|
|
import gtk
|
|
|
|
import gobject
|
|
|
|
import pango
|
|
|
|
|
2010-07-17 19:19:16 +02:00
|
|
|
import os
|
|
|
|
import traceback
|
2010-02-01 22:03:51 +01:00
|
|
|
import logging
|
|
|
|
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
|
|
|
log = logging.getLogger("logview")
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2010-08-15 18:43:30 +02:00
|
|
|
import gettext
|
|
|
|
trans = gettext.translation("fpdb", localedir="locale", languages=["de_DE"])
|
|
|
|
trans.install()
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-09 22:58:56 +01:00
|
|
|
MAX_LINES = 100000 # max lines to display in window
|
|
|
|
EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file
|
2010-03-09 23:36:03 +01:00
|
|
|
LOGFILES = [ [ 'Fpdb Errors', 'fpdb-errors.txt', False ] # label, filename, start value
|
|
|
|
, [ 'Fpdb Log', 'fpdb-log.txt', True ]
|
|
|
|
, [ 'HUD Errors', 'HUD-errors.txt', False ]
|
|
|
|
, [ 'HUD Log', 'HUD-log.txt', False ]
|
|
|
|
]
|
2009-12-05 21:10:00 +01:00
|
|
|
|
2009-12-05 16:54:49 +01:00
|
|
|
class GuiLogView:
|
|
|
|
|
2009-12-09 22:58:56 +01:00
|
|
|
def __init__(self, config, mainwin, closeq):
|
2009-12-05 16:54:49 +01:00
|
|
|
self.config = config
|
|
|
|
self.main_window = mainwin
|
2009-12-09 22:58:56 +01:00
|
|
|
self.closeq = closeq
|
2009-12-07 23:55:12 +01:00
|
|
|
|
2010-03-09 23:36:03 +01:00
|
|
|
self.logfile = os.path.join(self.config.dir_log, LOGFILES[1][1])
|
2010-08-15 18:43:30 +02:00
|
|
|
self.dia = gtk.Dialog(title=_("Log Messages")
|
2009-12-07 23:55:12 +01:00
|
|
|
,parent=None
|
|
|
|
,flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
|
|
|
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
|
|
|
|
self.dia.set_modal(False)
|
|
|
|
|
|
|
|
self.vbox = self.dia.vbox
|
2009-12-05 16:54:49 +01:00
|
|
|
gtk.Widget.set_size_request(self.vbox, 700, 400);
|
|
|
|
|
2009-12-05 21:10:00 +01:00
|
|
|
self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text
|
|
|
|
# this is how to add a filter:
|
|
|
|
#
|
|
|
|
# # Creation of the filter, from the model
|
|
|
|
# filter = self.liststore.filter_new()
|
|
|
|
# filter.set_visible_column(1)
|
|
|
|
#
|
|
|
|
# # The TreeView gets the filter as model
|
|
|
|
# self.listview = gtk.TreeView(filter)
|
2009-12-05 16:54:49 +01:00
|
|
|
self.listview = gtk.TreeView(model=self.liststore)
|
2009-12-05 21:10:00 +01:00
|
|
|
self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
|
2009-12-05 23:48:41 +01:00
|
|
|
self.listcols = []
|
2009-12-05 16:54:49 +01:00
|
|
|
|
|
|
|
scrolledwindow = gtk.ScrolledWindow()
|
|
|
|
scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
|
|
scrolledwindow.add(self.listview)
|
2009-12-05 23:48:41 +01:00
|
|
|
self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0)
|
|
|
|
|
2010-03-09 23:36:03 +01:00
|
|
|
hb = gtk.HBox(False, 0)
|
|
|
|
grp = None
|
|
|
|
for logf in LOGFILES:
|
|
|
|
rb = gtk.RadioButton(group=grp, label=logf[0], use_underline=True)
|
|
|
|
if grp is None: grp = rb
|
|
|
|
rb.set_active(logf[2])
|
|
|
|
rb.connect('clicked', self.__set_logfile, logf[0])
|
|
|
|
hb.pack_start(rb, False, False, 3)
|
2010-08-15 18:43:30 +02:00
|
|
|
refreshbutton = gtk.Button(_("Refresh"))
|
2009-12-05 23:48:41 +01:00
|
|
|
refreshbutton.connect("clicked", self.refresh, None)
|
2010-03-09 23:36:03 +01:00
|
|
|
hb.pack_start(refreshbutton, False, False, 3)
|
2009-12-05 23:48:41 +01:00
|
|
|
refreshbutton.show()
|
2010-03-09 23:36:03 +01:00
|
|
|
self.vbox.pack_start(hb, False, False, 0)
|
2009-12-05 16:54:49 +01:00
|
|
|
|
|
|
|
self.listview.show()
|
|
|
|
scrolledwindow.show()
|
|
|
|
self.vbox.show()
|
2009-12-07 23:55:12 +01:00
|
|
|
self.dia.set_focus(self.listview)
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-05 23:48:41 +01:00
|
|
|
col = self.addColumn("Date/Time", 0)
|
|
|
|
col = self.addColumn("Module", 1)
|
|
|
|
col = self.addColumn("Level", 2)
|
|
|
|
col = self.addColumn("Text", 3)
|
|
|
|
|
2009-12-05 16:54:49 +01:00
|
|
|
self.loadLog()
|
|
|
|
self.vbox.show_all()
|
2009-12-07 23:55:12 +01:00
|
|
|
self.dia.show()
|
|
|
|
|
|
|
|
self.dia.connect('response', self.dialog_response_cb)
|
|
|
|
|
2010-03-09 23:36:03 +01:00
|
|
|
def __set_logfile(self, w, file):
|
|
|
|
#print "w is", w, "file is", file, "active is", w.get_active()
|
|
|
|
if w.get_active():
|
|
|
|
for logf in LOGFILES:
|
|
|
|
if logf[0] == file:
|
|
|
|
self.logfile = os.path.join(self.config.dir_log, logf[1])
|
|
|
|
self.refresh(w, file) # params are not used
|
|
|
|
|
2009-12-07 23:55:12 +01:00
|
|
|
def dialog_response_cb(self, dialog, response_id):
|
|
|
|
# this is called whether close button is pressed or window is closed
|
2009-12-09 22:58:56 +01:00
|
|
|
self.closeq.put(self.__class__)
|
2009-12-07 23:55:12 +01:00
|
|
|
dialog.destroy()
|
|
|
|
|
|
|
|
def get_dialog(self):
|
|
|
|
return self.dia
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-05 23:48:41 +01:00
|
|
|
def addColumn(self, title, n):
|
|
|
|
col = gtk.TreeViewColumn(title)
|
|
|
|
self.listview.append_column(col)
|
|
|
|
cRender = gtk.CellRendererText()
|
|
|
|
cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
|
|
|
|
col.pack_start(cRender, True)
|
|
|
|
col.add_attribute(cRender, 'text', n)
|
|
|
|
col.set_max_width(1000)
|
|
|
|
col.set_spacing(0) # no effect
|
|
|
|
self.listcols.append(col)
|
|
|
|
col.set_clickable(True)
|
|
|
|
col.connect("clicked", self.sortCols, n)
|
|
|
|
return(col)
|
|
|
|
|
2009-12-05 16:54:49 +01:00
|
|
|
def loadLog(self):
|
|
|
|
|
|
|
|
self.liststore.clear()
|
2010-07-17 19:19:16 +02:00
|
|
|
# self.listcols = [] blanking listcols causes sortcols() to fail with index out of range
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-09 22:58:56 +01:00
|
|
|
# guesstimate number of lines in file
|
2010-02-01 22:03:51 +01:00
|
|
|
if os.path.exists(self.logfile):
|
|
|
|
stat_info = os.stat(self.logfile)
|
2009-12-09 22:58:56 +01:00
|
|
|
lines = stat_info.st_size / EST_CHARS_PER_LINE
|
2010-02-01 22:03:51 +01:00
|
|
|
#print "logview: size =", stat_info.st_size, "lines =", lines
|
2009-12-09 22:58:56 +01:00
|
|
|
|
|
|
|
# set startline to line number to start display from
|
|
|
|
startline = 0
|
|
|
|
if lines > MAX_LINES:
|
|
|
|
# only display from startline if log file is large
|
|
|
|
startline = lines - MAX_LINES
|
|
|
|
|
|
|
|
l = 0
|
2010-02-01 22:03:51 +01:00
|
|
|
for line in open(self.logfile):
|
2010-03-09 23:36:03 +01:00
|
|
|
# example line in logfile format:
|
2009-12-09 22:58:56 +01:00
|
|
|
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
|
|
|
|
l = l + 1
|
2010-03-09 23:36:03 +01:00
|
|
|
if l > startline:
|
2010-07-17 19:19:16 +02:00
|
|
|
# NOTE selecting a sort column and then switching to a log file
|
|
|
|
# with several thousand rows will send cpu 100% for a prolonged period.
|
|
|
|
# reason is that the append() method seems to sort every record as it goes, rather than
|
|
|
|
# pulling in the whole file and sorting at the end.
|
|
|
|
# one fix is to check if a column sort has been selected, reset to date/time asc
|
|
|
|
# append all the rows and then reselect the required sort order.
|
|
|
|
# Note: there is no easy method available to revert the list to an "unsorted" state.
|
|
|
|
# always defaulting to date/time asc doesn't work, because some rows do not have date/time info
|
|
|
|
# and would end up sorted out of context.
|
2010-03-09 23:36:03 +01:00
|
|
|
if len(line) > 49 and line[23:26] == ' - ' and line[34:39] == ' ':
|
|
|
|
iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
|
|
|
|
else:
|
|
|
|
iter = self.liststore.append( ('', '', '', line.strip(), True) )
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-05 21:10:00 +01:00
|
|
|
def sortCols(self, col, n):
|
|
|
|
try:
|
|
|
|
if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
|
|
|
|
col.set_sort_order(gtk.SORT_DESCENDING)
|
|
|
|
else:
|
|
|
|
col.set_sort_order(gtk.SORT_ASCENDING)
|
|
|
|
self.liststore.set_sort_column_id(n, col.get_sort_order())
|
|
|
|
#self.liststore.set_sort_func(n, self.sortnums, (n,grid))
|
|
|
|
for i in xrange(len(self.listcols)):
|
|
|
|
self.listcols[i].set_sort_indicator(False)
|
|
|
|
self.listcols[n].set_sort_indicator(True)
|
|
|
|
# use this listcols[col].set_sort_indicator(True)
|
|
|
|
# to turn indicator off for other cols
|
|
|
|
except:
|
|
|
|
err = traceback.extract_tb(sys.exc_info()[2])
|
2010-08-15 18:43:30 +02:00
|
|
|
print _("***sortCols error: ") + str(sys.exc_info()[1])
|
2009-12-05 21:10:00 +01:00
|
|
|
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
2009-12-05 16:54:49 +01:00
|
|
|
|
2009-12-05 23:48:41 +01:00
|
|
|
def refresh(self, widget, data):
|
|
|
|
self.loadLog()
|
|
|
|
|
2009-12-05 16:54:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__=="__main__":
|
|
|
|
|
|
|
|
config = Configuration.Config()
|
|
|
|
|
|
|
|
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
2010-08-15 18:43:30 +02:00
|
|
|
win.set_title(_("Test Log Viewer"))
|
2009-12-05 16:54:49 +01:00
|
|
|
win.set_border_width(1)
|
|
|
|
win.set_default_size(600, 500)
|
|
|
|
win.set_resizable(True)
|
|
|
|
|
2010-08-15 18:43:30 +02:00
|
|
|
dia = gtk.Dialog(_("Log Viewer"),
|
2009-12-05 16:54:49 +01:00
|
|
|
win,
|
|
|
|
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
|
|
|
|
dia.set_default_size(500, 500)
|
|
|
|
log = GuiLogView(config, win, dia.vbox)
|
|
|
|
response = dia.run()
|
|
|
|
if response == gtk.RESPONSE_ACCEPT:
|
|
|
|
pass
|
|
|
|
dia.destroy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|