From 6826d0157a82cf7811396aac6b90d4a0626378c5 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 15:54:49 +0000 Subject: [PATCH 1/6] create gui option to view the log --- pyfpdb/GuiLogView.py | 129 +++++++++++++++++++++++++++++++++++++++++++ pyfpdb/fpdb.py | 31 ++++++++++- pyfpdb/logging.conf | 14 ++++- 3 files changed, 172 insertions(+), 2 deletions(-) create mode 100755 pyfpdb/GuiLogView.py diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py new file mode 100755 index 00000000..77f09b06 --- /dev/null +++ b/pyfpdb/GuiLogView.py @@ -0,0 +1,129 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#Copyright 2008 Carl Gherardi +#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 . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + + +import xml.dom.minidom +from xml.dom.minidom import Node + +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import pango + +import Configuration + +log = Configuration.get_logger("logging.conf", "logview") + +class GuiLogView: + + def __init__(self, config, mainwin, vbox): + self.config = config + self.main_window = mainwin + self.vbox = vbox + gtk.Widget.set_size_request(self.vbox, 700, 400); + + self.liststore = gtk.ListStore(str, str, str, str) # date, module, level, text + self.listview = gtk.TreeView(model=self.liststore) + self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) + + scrolledwindow = gtk.ScrolledWindow() + scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) + scrolledwindow.add(self.listview) + + self.listview.show() + scrolledwindow.show() + self.vbox.show() + + self.loadLog() + self.vbox.show_all() + + def loadLog(self): + + #self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) + #self.configView = gtk.TreeView(self.configStore) + #self.configView.set_enable_tree_lines(True) + self.liststore.clear() + + col = gtk.TreeViewColumn("Date/Time") + 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', 0) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Module") + 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', 1) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Level") + 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', 2) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Text") + 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', 3) + col.set_max_width(1000) + + l = 0 + for line in open('logging.out', 'r'): + #self.addLogText(line) + iter = self.liststore.append([line.strip(), "", "", ""]) + l = l + 1 + if l >= 100: + break + + + +if __name__=="__main__": + + config = Configuration.Config() + + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_title("Test Log Viewer") + win.set_border_width(1) + win.set_default_size(600, 500) + win.set_resizable(True) + + dia = gtk.Dialog("Log Viewer", + 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() + + + + diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index faaf4fdc..79567578 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -60,7 +60,8 @@ if not options.errorsToConsole: errorFile = open('fpdb-error-log.txt', 'w', 0) sys.stderr = errorFile -import logging +#import logging +import logging, logging.config import pygtk pygtk.require('2.0') @@ -70,6 +71,7 @@ import interlocks import GuiPrefs +import GuiLogView import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -85,6 +87,8 @@ import Exceptions VERSION = "0.12" +log = Configuration.get_logger("logging.conf", "fpdb") + class fpdb: def tab_clicked(self, widget, tab_name): """called when a tab button is clicked to activate that tab""" @@ -413,6 +417,29 @@ class fpdb: self.release_global_lock() + def dia_logs(self, widget, data=None): + lock_set = False + if self.obtain_global_lock(): + lock_set = True + + dia = gtk.Dialog(title="Log Messages" + ,parent=None + ,flags=0 + ,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK)) + logviewer = GuiLogView.GuiLogView(self.config, self.window, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + pass + dia.destroy() + + if lock_set: + self.release_global_lock() + + def addLogText(self, text): + end_iter = self.logbuffer.get_end_iter() + self.logbuffer.insert(end_iter, text) + self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0) + def __calendar_dialog(self, widget, entry): self.dia_confirm.set_modal(False) d = gtk.Window(gtk.WINDOW_TOPLEVEL) @@ -515,6 +542,7 @@ class fpdb: + @@ -556,6 +584,7 @@ class fpdb: ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), ('help', None, '_Help'), ('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations), + ('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs), ('About', None, 'A_bout', None, 'About the program', self.dia_about), ('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing), ]) diff --git a/pyfpdb/logging.conf b/pyfpdb/logging.conf index 124b509d..1b54b453 100644 --- a/pyfpdb/logging.conf +++ b/pyfpdb/logging.conf @@ -11,6 +11,18 @@ keys=fileFormatter,stderrFormatter level=INFO handlers=consoleHandler,fileHandler +[logger_fpdb] +level=INFO +handlers=consoleHandler,fileHandler +qualname=fpdb +propagate=0 + +[logger_logview] +level=INFO +handlers=consoleHandler,fileHandler +qualname=logview +propagate=0 + [logger_parser] level=INFO handlers=consoleHandler,fileHandler @@ -24,7 +36,7 @@ qualname=importer propagate=0 [logger_config] -level=DEBUG +level=INFO handlers=consoleHandler,fileHandler qualname=config propagate=0 From 2d8c44110c5a77bac5823e301b9bc74dac4d42f1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 20:10:00 +0000 Subject: [PATCH 2/6] refine log viewer --- pyfpdb/GuiLogView.py | 90 +++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 77f09b06..646ccb0e 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -30,6 +30,8 @@ import Configuration log = Configuration.get_logger("logging.conf", "logview") +MAX_LINES = 1000 + class GuiLogView: def __init__(self, config, mainwin, vbox): @@ -38,9 +40,19 @@ class GuiLogView: self.vbox = vbox gtk.Widget.set_size_request(self.vbox, 700, 400); - self.liststore = gtk.ListStore(str, str, str, str) # date, module, level, text + 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) + self.listview = gtk.TreeView(model=self.liststore) - self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) + self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) @@ -60,47 +72,55 @@ class GuiLogView: #self.configView = gtk.TreeView(self.configStore) #self.configView.set_enable_tree_lines(True) self.liststore.clear() + self.listcols = [] - col = gtk.TreeViewColumn("Date/Time") - 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', 0) - col.set_max_width(1000) + col = self.addColumn("Date/Time", 0) - col = gtk.TreeViewColumn("Module") - 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', 1) - col.set_max_width(1000) - - col = gtk.TreeViewColumn("Level") - 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', 2) - col.set_max_width(1000) - - col = gtk.TreeViewColumn("Text") - 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', 3) - col.set_max_width(1000) + col = self.addColumn("Module", 1) + col = self.addColumn("Level", 2) + col = self.addColumn("Text", 3) l = 0 for line in open('logging.out', 'r'): - #self.addLogText(line) - iter = self.liststore.append([line.strip(), "", "", ""]) + # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised + if len(line) > 49: + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) l = l + 1 - if l >= 100: + if l >= MAX_LINES: break + 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) + + 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]) + print "***sortCols error: " + str(sys.exc_info()[1]) + print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) + if __name__=="__main__": From 2934c3213265813859bd097a818dfc4660b202d1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 20:31:37 +0000 Subject: [PATCH 3/6] limit number of lines displayed in log viewer --- pyfpdb/GuiLogView.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 646ccb0e..0f7f03c7 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -17,8 +17,7 @@ #agpl-3.0.txt in the docs folder of the package. -import xml.dom.minidom -from xml.dom.minidom import Node +import mmap import pygtk pygtk.require('2.0') @@ -30,7 +29,7 @@ import Configuration log = Configuration.get_logger("logging.conf", "logview") -MAX_LINES = 1000 +MAX_LINES = 100000 class GuiLogView: @@ -80,14 +79,33 @@ class GuiLogView: col = self.addColumn("Level", 2) col = self.addColumn("Text", 3) + # count number of lines in file + f = open('logging.out', "r+") + buf = mmap.mmap(f.fileno(), 0) + readline = buf.readline + lines = 0 + while readline(): + lines += 1 + f.close() + + startline = 0 + if lines > MAX_LINES: + # only display from startline if log file is large + startline = lines - MAX_LINES + + f = open('logging.out', "r+") + buf = mmap.mmap(f.fileno(), 0) + readline = buf.readline l = 0 - for line in open('logging.out', 'r'): + line = readline() + while line: + # eg line: # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised - if len(line) > 49: - iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) l = l + 1 - if l >= MAX_LINES: - break + if l > startline and len(line) > 49: + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) + line = readline() + f.close() def addColumn(self, title, n): col = gtk.TreeViewColumn(title) From 85242f13cb1a4d66d564d9368f1034d33c730bdf Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 21:59:42 +0000 Subject: [PATCH 4/6] fix bug with hud stats, must use ORDER BY in the selects --- pyfpdb/SQL.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index eb9296ef..5a0d1965 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1317,6 +1317,7 @@ class Sql: 1.25 would be a config value so user could change it) */ GROUP BY hc.PlayerId, hp.seatNo, p.name + ORDER BY hc.PlayerId, hp.seatNo, p.name """ # same as above except stats are aggregated for all blind/limit levels @@ -1418,6 +1419,7 @@ class Sql: ) ) GROUP BY hc.PlayerId, p.name + ORDER BY hc.PlayerId, p.name """ # NOTES on above cursor: # - Do NOT include %s inside query in a comment - the db api thinks From 18b0a47555fd96246f4ad1db4134a9fd90b817e4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 22:20:44 +0000 Subject: [PATCH 5/6] move print message to log --- pyfpdb/Database.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1c44bb61..36fdd2d2 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -474,8 +474,9 @@ class Database: else: h_seats_min, h_seats_max = 0, 10 print "bad h_seats_style value:", h_seats_style - print "opp seats style", seats_style, "hero seats style", h_seats_style - print "opp seats:", seats_min, seats_max, " hero seats:", h_seats_min, h_seats_max + log.info("opp seats style %s %d %d hero seats style %s %d %d" + % (seats_style, seats_min, seats_max + ,h_seats_style, h_seats_min, h_seats_max) ) if hud_style == 'S' or h_hud_style == 'S': self.get_stats_from_hand_session(hand, stat_dict, hero_id From 66b4ed35e538967073456cc9a0c0d148dadbc146 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 22:48:41 +0000 Subject: [PATCH 6/6] add refresh button to log viewer --- pyfpdb/GuiLogView.py | 50 +++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 0f7f03c7..3b7b8aa6 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -52,19 +52,44 @@ class GuiLogView: self.listview = gtk.TreeView(model=self.liststore) self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) + self.listcols = [] scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) scrolledwindow.add(self.listview) + self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) + + refreshbutton = gtk.Button("Refresh") + refreshbutton.connect("clicked", self.refresh, None) + self.vbox.pack_start(refreshbutton, False, False, 3) + refreshbutton.show() self.listview.show() scrolledwindow.show() self.vbox.show() + col = self.addColumn("Date/Time", 0) + col = self.addColumn("Module", 1) + col = self.addColumn("Level", 2) + col = self.addColumn("Text", 3) + self.loadLog() self.vbox.show_all() + 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) + def loadLog(self): #self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) @@ -73,12 +98,6 @@ class GuiLogView: self.liststore.clear() self.listcols = [] - col = self.addColumn("Date/Time", 0) - - col = self.addColumn("Module", 1) - col = self.addColumn("Level", 2) - col = self.addColumn("Text", 3) - # count number of lines in file f = open('logging.out', "r+") buf = mmap.mmap(f.fileno(), 0) @@ -107,20 +126,6 @@ class GuiLogView: line = readline() f.close() - 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) - def sortCols(self, col, n): try: if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING: @@ -139,6 +144,9 @@ class GuiLogView: print "***sortCols error: " + str(sys.exc_info()[1]) print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) + def refresh(self, widget, data): + self.loadLog() + if __name__=="__main__":