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