logviewer: avoid memory-mapped files, make it work when opened a second time
This commit is contained in:
parent
bbaecc1697
commit
fc95de82f4
|
@ -17,8 +17,8 @@
|
|||
#agpl-3.0.txt in the docs folder of the package.
|
||||
|
||||
|
||||
import mmap
|
||||
import threading
|
||||
import os
|
||||
import Queue
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
@ -30,13 +30,16 @@ import Configuration
|
|||
|
||||
log = Configuration.get_logger("logging.conf", "logview")
|
||||
|
||||
MAX_LINES = 100000
|
||||
MAX_LINES = 100000 # max lines to display in window
|
||||
EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file
|
||||
logfile = 'logging.out' # name of logfile
|
||||
|
||||
class GuiLogView:
|
||||
|
||||
def __init__(self, config, mainwin):
|
||||
def __init__(self, config, mainwin, closeq):
|
||||
self.config = config
|
||||
self.main_window = mainwin
|
||||
self.closeq = closeq
|
||||
|
||||
self.dia = gtk.Dialog(title="Log Messages"
|
||||
,parent=None
|
||||
|
@ -88,6 +91,7 @@ class GuiLogView:
|
|||
|
||||
def dialog_response_cb(self, dialog, response_id):
|
||||
# this is called whether close button is pressed or window is closed
|
||||
self.closeq.put(self.__class__)
|
||||
dialog.destroy()
|
||||
|
||||
def get_dialog(self):
|
||||
|
@ -109,39 +113,28 @@ class GuiLogView:
|
|||
|
||||
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()
|
||||
self.listcols = []
|
||||
|
||||
# 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()
|
||||
# guesstimate number of lines in file
|
||||
if os.path.exists(logfile):
|
||||
stat_info = os.stat(logfile)
|
||||
lines = stat_info.st_size / EST_CHARS_PER_LINE
|
||||
print "logview: size =", stat_info.st_size, "lines =", lines
|
||||
|
||||
startline = 0
|
||||
if lines > MAX_LINES:
|
||||
# only display from startline if log file is large
|
||||
startline = lines - MAX_LINES
|
||||
# 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
|
||||
|
||||
f = open('logging.out', "r+")
|
||||
buf = mmap.mmap(f.fileno(), 0)
|
||||
readline = buf.readline
|
||||
l = 0
|
||||
line = readline()
|
||||
while line:
|
||||
# eg line:
|
||||
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
|
||||
l = l + 1
|
||||
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()
|
||||
l = 0
|
||||
for line in open(logfile):
|
||||
# eg line:
|
||||
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
|
||||
l = l + 1
|
||||
if l > startline and len(line) > 49:
|
||||
iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
|
||||
|
||||
def sortCols(self, col, n):
|
||||
try:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
import Queue
|
||||
|
||||
# if path is set to use an old version of python look for a new one:
|
||||
# (does this work in linux?)
|
||||
|
@ -485,14 +486,22 @@ class fpdb:
|
|||
#if self.obtain_global_lock():
|
||||
# lock_set = True
|
||||
|
||||
# remove members from self.threads if close messages received
|
||||
self.process_close_messages()
|
||||
|
||||
viewer = None
|
||||
for i, t in enumerate(self.threads):
|
||||
if str(t.__class__) == 'GuiLogView.GuiLogView':
|
||||
# show existing log window
|
||||
t.get_dialog().present()
|
||||
return
|
||||
viewer = t
|
||||
break
|
||||
|
||||
new_thread = GuiLogView.GuiLogView(self.config, self.window)
|
||||
self.threads.append(new_thread)
|
||||
if viewer is None:
|
||||
#print "creating new log viewer"
|
||||
new_thread = GuiLogView.GuiLogView(self.config, self.window, self.closeq)
|
||||
self.threads.append(new_thread)
|
||||
else:
|
||||
#print "showing existing log viewer"
|
||||
viewer.get_dialog().present()
|
||||
|
||||
#if lock_set:
|
||||
# self.release_global_lock()
|
||||
|
@ -502,6 +511,21 @@ class fpdb:
|
|||
self.logbuffer.insert(end_iter, text)
|
||||
self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0)
|
||||
|
||||
|
||||
def process_close_messages(self):
|
||||
# check for close messages
|
||||
try:
|
||||
while True:
|
||||
name = self.closeq.get(False)
|
||||
for i, t in enumerate(self.threads):
|
||||
if str(t.__class__) == str(name):
|
||||
# thread has ended so remove from list:
|
||||
del self.threads[i]
|
||||
break
|
||||
except Queue.Empty:
|
||||
# no close messages on queue, do nothing
|
||||
pass
|
||||
|
||||
def __calendar_dialog(self, widget, entry):
|
||||
self.dia_confirm.set_modal(False)
|
||||
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
|
@ -846,6 +870,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
#done menubar
|
||||
|
||||
self.threads = [] # objects used by tabs - no need for threads, gtk handles it
|
||||
self.closeq = Queue.Queue(20) # used to signal ending of a thread (only logviewer for now)
|
||||
|
||||
self.nb = gtk.Notebook()
|
||||
self.nb.set_show_tabs(True)
|
||||
|
|
Loading…
Reference in New Issue
Block a user