changeset 749:3dba26fcfde0

moved logfile/logfile.py to logfile/__init__.py
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Wed, 07 Jun 2006 09:44:08 +0200
parents bff32ecb8a57
children f158c4e8fea2
files MoinMoin/logfile/__init__.py MoinMoin/logfile/editlog.py MoinMoin/logfile/eventlog.py MoinMoin/logfile/logfile.py MoinMoin/macro/PageHits.py MoinMoin/stats/hitcounts.py MoinMoin/stats/useragents.py MoinMoin/wikidicts.py docs/CHANGES
diffstat 9 files changed, 416 insertions(+), 422 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/logfile/__init__.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/logfile/__init__.py	Wed Jun 07 09:44:08 2006 +0200
@@ -10,3 +10,409 @@
 
 logfiles = pysupport.getPackageModules(__file__)
 
+import os, codecs, errno
+from MoinMoin import config, wikiutil
+
+class LogError(Exception):
+    """ Base class for log errors """
+
+class LogMissing(LogError):
+    """ Raised when the log is missing """
+
+
+class LineBuffer:
+    """
+    Reads lines from a file
+      self.lines    list of lines (Strings) 
+      self.offsets  list of offset for each line
+    """
+    def __init__(self, file, offset, size, forward=True):
+        """
+        @param file: open file object
+        @param offset: position in file to start from
+        @param size: aproximate number of bytes to read
+        @param forward : read from offset on or from offset-size to offset
+        @type forward: boolean
+        """
+        if forward:
+            file.seek(offset)
+            self.lines = file.readlines(size)
+            self.__calculate_offsets(offset)
+        else:
+            if offset < 2 * size:
+                begin = 0
+            else:
+                begin = offset - size
+            file.seek(begin)
+            self.lines = file.read(offset-begin).splitlines(True)
+            if begin != 0:
+                begin += len(self.lines[0])
+                self.lines = self.lines[1:]
+                # XXX check for min one line read
+            self.__calculate_offsets(begin)
+
+        # Decode lines after offset in file is calculated
+        self.lines = [unicode(line, config.charset) for line in self.lines]
+        self.len = len(self.lines)
+
+    def __calculate_offsets(self, offset):
+        """
+        @param offset: offset of the first line
+        """
+        self.offsets = map(lambda x:len(x), self.lines)
+        self.offsets.append(0)
+        i = 1
+        length = len(self.offsets)
+        tmp = offset
+        while i < length:
+            result = self.offsets[i-1] + tmp
+            tmp = self.offsets[i]
+            self.offsets[i] =  result
+            i = i + 1
+        self.offsets[0] = offset
+
+
+class LogFile:
+    """
+    .filter: function that gets the values from .parser.
+       must return True to keep it or False to remove it
+    Overwrite .parser() and .add() to customize this class to
+    special log files
+    """
+    
+    def __init__(self, filename, buffer_size=65536):
+        """
+        @param filename: name of the log file
+        @param buffer_size: approx. size of one buffer in bytes
+        """
+        self.buffer_size = buffer_size
+        self.__filename = filename
+        self.filter = None
+        self.__lineno = 0
+        self.__buffer = None
+        self.__buffer1 = None
+        self.__buffer2 = None
+
+    def __iter__(self):
+        return self
+
+    def reverse(self):
+        """ @rtype: iterator
+        """
+        self.to_end()
+        while 1:
+            try:
+                result = self.previous()
+            except StopIteration:
+                return
+            yield result
+            
+    def sanityCheck(self):
+        """ Check for log file write access.
+        
+        TODO: os.access should not be used here.
+        
+        @rtype: string (error message) or None
+        """
+        if not os.access(self.__filename, os.W_OK):
+            return "The log '%s' is not writable!" % (self.__filename,)
+        return None
+
+    def __getattr__(self, name):
+        """
+        generate some attributes when needed
+        """
+        if name=="_LogFile__rel_index":
+            # starting iteration from begin
+            self.__buffer1 = LineBuffer(self._input, 0, self.buffer_size)
+            self.__buffer2 = LineBuffer(self._input,
+                                        self.__buffer1.offsets[-1],
+                                        self.buffer_size)
+            self.__buffer = self.__buffer1
+            self.__rel_index = 0
+            return 0
+        elif name == "_input":
+            try:
+                # Open the file without codecs.open, it break our offset
+                # calculation. We decode it later.
+                # Use binary mode in order to retain \r. Otherwise the offset
+                # calculation would fail
+                self._input = file(self.__filename, "rb",)
+            except IOError:
+                raise StopIteration
+            return self._input
+        elif name == "_output":
+            self._output = codecs.open(self.__filename, 'a', config.charset)
+            try:
+                os.chmod(self.__filename, 0666 & config.umask)
+            except OSError:
+                # TODO: should not ignore errors like this!
+                pass
+            return self._output
+        else:
+            raise AttributeError(name)
+
+    def size(self):
+        """ Return log size in bytes
+        
+        Return 0 if the file does not exists. Raises other OSError.
+        
+        @return: size of log file in bytes
+        @rtype: Int
+        """
+        try:
+            return os.path.getsize(self.__filename)
+        except OSError, err:
+            if err.errno == errno.ENOENT:
+                return 0            
+            raise
+
+    def lines(self):
+        """ Return number of lines in the log file
+        
+        Return 0 if the file does not exists. Raises other OSError.
+
+        Expensive for big log files - O(n)
+        
+        @return: size of log file in lines
+        @rtype: Int
+        """
+        try:
+            f = codecs.open(self.__filename, 'r')
+            try:
+                count = 0
+                for line in f:
+                    count += 1
+                return count
+            finally:
+                f.close()
+        except (OSError, IOError), err:
+            if err.errno == errno.ENOENT:
+                return 0
+            raise
+
+    def date(self):
+        """ Return timestamp of log file in usecs """
+        try:
+            mtime = os.path.getmtime(self.__filename)            
+        except OSError, err:
+            if err.errno == errno.ENOENT:
+                # This can happen on fresh wiki when building the index
+                # Usually the first request will create an event log
+                raise LogMissing(str(err))
+            raise
+        return wikiutil.timestamp2version(mtime)
+
+    def peek(self, lines):
+        """ What does this method do?
+
+        @param lines: number of lines, may be negative to move backward 
+            moves file position by lines.
+        @return: True if moving more than (WHAT?) to the beginning and moving
+            to the end or beyond
+        @rtype: boolean
+        peek adjusts .__lineno if set
+        This function is not aware of filters!
+        """
+        self.__rel_index = self.__rel_index + lines
+        while self.__rel_index < 0:
+            if self.__buffer == self.__buffer2:
+                # change to buffer 1
+                self.__buffer = self.__buffer1
+                self.__rel_index = self.__rel_index + self.__buffer.len
+            else:
+                if self.__buffer.offsets[0] == 0:
+                    # already at the beginning of the file
+                    # XXX
+                    self.__rel_index = 0
+                    self.__lineno = 0
+                    return True
+                else:
+                    # load previous lines
+                    self.__buffer2 = self.__buffer1
+                    self.__buffer1 = LineBuffer(self._input,
+                                                self.__buffer2.offsets[0],
+                                                self.buffer_size,
+                                                forward=False)
+                    self.__rel_index = (self.__rel_index +
+                                        self.__buffer1.len)
+                    self.__buffer = self.__buffer1
+                
+        while self.__rel_index >= self.__buffer.len:
+            if self.__buffer == self.__buffer1:
+                # change to buffer 2
+                self.__rel_index = self.__rel_index - self.__buffer.len
+                self.__buffer = self.__buffer2
+            else:
+                # try to load next buffer
+                tmpbuff = LineBuffer(self._input,
+                                     self.__buffer1.offsets[-1],
+                                     self.buffer_size)
+                if tmpbuff.len==0:
+                    # end of file
+                    if self.__lineno:
+                        self.__lineno = (self.__lineno + lines -
+                                         (self.__rel_index -
+                                          len(self.__buffer.offsets)))
+                    self.__rel_index = len(self.__buffer.offsets)
+                    return True
+                # shift buffers
+                self.__buffer1 = self.__buffer2
+                self.__buffer2 = tmpbuff                
+                self.__rel_index = self.__rel_index - self.__buffer1.len
+        if self.__lineno: self.__lineno += lines
+        return False
+
+    def __next(self):
+        """get next line already parsed"""
+        if self.peek(0):
+            raise StopIteration
+        result = self.parser(self.__buffer.lines[self.__rel_index])
+        self.peek(1)
+        return result
+
+    def next(self):
+        """
+        @return: next entry
+        raises StopIteration at file end
+        XXX It does not raise anything!
+        """
+        result = None
+        while result == None:
+            while result == None:
+                result = self.__next()
+            if self.filter and not self.filter(result):
+                result = None
+        return result
+    
+    def __previous(self):
+        if self.peek(-1): raise StopIteration
+        return self.parser(self.__buffer.lines[self.__rel_index])
+
+    def previous(self):
+        """
+        @return: previous entry and moves file position one line back
+        raises StopIteration at file begin
+        """
+        result = None
+        while result == None:
+            while result == None:
+                result = self.__previous()
+            if self.filter and not self.filter(result):
+                result = None
+        return result
+
+    def to_begin(self):
+        """moves file position to the begin"""
+        if self.__buffer1.offsets[0] != 0:
+            self.__buffer1 = LineBuffer(self._input,
+                                        0,
+                                        self.buffer_size)
+            self.__buffer2 = LineBuffer(self._input,
+                                        self.__buffer1.offsets[-1],
+                                        self.buffer_size)
+        self.__buffer = self.__buffer1
+        self.__rel_index = 0
+        self.__lineno = 0
+
+    def to_end(self):
+        """moves file position to the end"""
+        self._input.seek(0, 2) # to end of file
+        size = self._input.tell()
+        if (not self.__buffer2) or (size>self.__buffer2.offsets[-1]):
+            self.__buffer2 = LineBuffer(self._input,
+                                        size,
+                                        self.buffer_size,
+                                        forward = False)
+            
+            self.__buffer1 = LineBuffer(self._input,
+                                        self.__buffer2.offsets[0],
+                                        self.buffer_size,
+                                        forward = False)
+        self.__buffer = self.__buffer2
+        self.__rel_index = self.__buffer2.len
+        self.__lineno = None
+
+    def position(self):
+        """ Return the current file position
+        
+        This can be converted into a String using back-ticks and then
+        be rebuild.
+        For this plain file implementation position is an Integer.
+        """
+        return self.__buffer.offsets[self.__rel_index]
+        
+    def seek(self, position, line_no=None):
+        """ moves file position to an value formerly gotten from .position().
+        To enable line counting line_no must be provided.
+        .seek is much more efficient for moving long distances than .peek.
+        raises ValueError if position is invalid
+        """
+        if self.__buffer1.offsets[0] <= position < self.__buffer1.offsets[-1]:
+            # position is in .__buffer1 
+            self.__rel_index = self.__buffer1.offsets.index(position)
+            self.__buffer = self.__buffer1
+        elif (self.__buffer2.offsets[0] <= position <
+              self.__buffer2.offsets[-1]):
+            # position is in .__buffer2
+            self.__rel_index = self.__buffer2.offsets.index(position)
+            self.__buffer = self.__buffer2
+        else:
+            # load buffers around position
+            self.__buffer1 = LineBuffer(self._input,
+                                        position,
+                                        self.buffer_size,
+                                        forward = False)
+            self.__buffer2 = LineBuffer(self._input,
+                                        position,
+                                        self.buffer_size)
+            self.__buffer = self.__buffer2
+            self.__rel_index = 0
+            # XXX test for valid position
+        self.__lineno = line_no
+
+    def line_no(self):
+        """@return: the current line number or None if line number is unknown"""
+        return self.__lineno
+    
+    def calculate_line_no(self):
+        """ Calculate the current line number from buffer offsets
+        
+        If line number is unknown it is calculated by parsing the whole file.
+        This may be expensive.
+        """
+        self._input.seek(0, 0)
+        lines = self._input.read(self.__buffer.offsets[self.__rel_index])
+        self.__lineno = len(lines.splitlines())
+        return self.__lineno
+
+    def parser(self, line):
+        """
+        @param line: line as read from file
+        @return: parsed line or None on error
+        Converts the line from file to program representation
+        This implementation uses TAB separated strings.
+        This method should be overwritten by the sub classes.
+        """
+        return line.split("\t")
+
+    def add(self, *data):
+        """
+        add line to log file
+        This implementation save the values as TAB separated strings.
+        This method should be overwritten by the sub classes.
+        """
+        line = "\t".join(data)
+        self._add(line)
+        
+    def _add(self, line):
+        """
+        @param line: flat line
+        @type line: String
+        write on entry in the log file
+        """
+        if line != None:
+            if line[-1] != '\n':
+                line += '\n'
+            self._output.write(line)
+
--- a/MoinMoin/logfile/editlog.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/logfile/editlog.py	Wed Jun 07 09:44:08 2006 +0200
@@ -5,7 +5,7 @@
 """
 
 import os.path
-from logfile import LogFile
+from MoinMoin.logfile import LogFile
 from MoinMoin import wikiutil, user, config
 from MoinMoin.Page import Page
 
--- a/MoinMoin/logfile/eventlog.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/logfile/eventlog.py	Wed Jun 07 09:44:08 2006 +0200
@@ -5,7 +5,7 @@
 """
 
 import os.path, time
-from logfile import LogFile
+from MoinMoin.logfile import LogFile
 from MoinMoin import util, config, wikiutil
 from MoinMoin.util import web
 
--- a/MoinMoin/logfile/logfile.py	Tue Jun 06 23:07:08 2006 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-"""
-    MoinMoin basic log stuff
-
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import os, codecs, errno
-from MoinMoin import config, wikiutil
-
-class LogError(Exception):
-    """ Base class for log errors """
-
-class LogMissing(LogError):
-    """ Raised when the log is missing """
-
-
-class LineBuffer:
-    """
-    Reads lines from a file
-      self.lines    list of lines (Strings) 
-      self.offsets  list of offset for each line
-    """
-    def __init__(self, file, offset, size, forward=True):
-        """
-        @param file: open file object
-        @param offset: position in file to start from
-        @param size: aproximate number of bytes to read
-        @param forward : read from offset on or from offset-size to offset
-        @type forward: boolean
-        """
-        if forward:
-            file.seek(offset)
-            self.lines = file.readlines(size)
-            self.__calculate_offsets(offset)
-        else:
-            if offset < 2 * size:
-                begin = 0
-            else:
-                begin = offset - size
-            file.seek(begin)
-            self.lines = file.read(offset-begin).splitlines(True)
-            if begin != 0:
-                begin += len(self.lines[0])
-                self.lines = self.lines[1:]
-                # XXX check for min one line read
-            self.__calculate_offsets(begin)
-
-        # Decode lines after offset in file is calculated
-        self.lines = [unicode(line, config.charset) for line in self.lines]
-        self.len = len(self.lines)
-
-    def __calculate_offsets(self, offset):
-        """
-        @param offset: offset of the first line
-        """
-        self.offsets = map(lambda x:len(x), self.lines)
-        self.offsets.append(0)
-        i = 1
-        length = len(self.offsets)
-        tmp = offset
-        while i < length:
-            result = self.offsets[i-1] + tmp
-            tmp = self.offsets[i]
-            self.offsets[i] =  result
-            i = i + 1
-        self.offsets[0] = offset
-
-
-class LogFile:
-    """
-    .filter: function that gets the values from .parser.
-       must return True to keep it or False to remove it
-    Overwrite .parser() and .add() to customize this class to
-    special log files
-    """
-    
-    def __init__(self, filename, buffer_size=65536):
-        """
-        @param filename: name of the log file
-        @param buffer_size: approx. size of one buffer in bytes
-        """
-        self.buffer_size = buffer_size
-        self.__filename = filename
-        self.filter = None
-        self.__lineno = 0
-        self.__buffer = None
-        self.__buffer1 = None
-        self.__buffer2 = None
-
-    def __iter__(self):
-        return self
-
-    def reverse(self):
-        """ @rtype: iterator
-        """
-        self.to_end()
-        while 1:
-            try:
-                result = self.previous()
-            except StopIteration:
-                return
-            yield result
-            
-    def sanityCheck(self):
-        """ Check for log file write access.
-        
-        TODO: os.access should not be used here.
-        
-        @rtype: string (error message) or None
-        """
-        if not os.access(self.__filename, os.W_OK):
-            return "The log '%s' is not writable!" % (self.__filename,)
-        return None
-
-    def __getattr__(self, name):
-        """
-        generate some attributes when needed
-        """
-        if name=="_LogFile__rel_index":
-            # starting iteration from begin
-            self.__buffer1 = LineBuffer(self._input, 0, self.buffer_size)
-            self.__buffer2 = LineBuffer(self._input,
-                                        self.__buffer1.offsets[-1],
-                                        self.buffer_size)
-            self.__buffer = self.__buffer1
-            self.__rel_index = 0
-            return 0
-        elif name == "_input":
-            try:
-                # Open the file without codecs.open, it break our offset
-                # calculation. We decode it later.
-                # Use binary mode in order to retain \r. Otherwise the offset
-                # calculation would fail
-                self._input = file(self.__filename, "rb",)
-            except IOError:
-                raise StopIteration
-            return self._input
-        elif name == "_output":
-            self._output = codecs.open(self.__filename, 'a', config.charset)
-            try:
-                os.chmod(self.__filename, 0666 & config.umask)
-            except OSError:
-                # TODO: should not ignore errors like this!
-                pass
-            return self._output
-        else:
-            raise AttributeError(name)
-
-    def size(self):
-        """ Return log size in bytes
-        
-        Return 0 if the file does not exists. Raises other OSError.
-        
-        @return: size of log file in bytes
-        @rtype: Int
-        """
-        try:
-            return os.path.getsize(self.__filename)
-        except OSError, err:
-            if err.errno == errno.ENOENT:
-                return 0            
-            raise
-
-    def lines(self):
-        """ Return number of lines in the log file
-        
-        Return 0 if the file does not exists. Raises other OSError.
-
-        Expensive for big log files - O(n)
-        
-        @return: size of log file in lines
-        @rtype: Int
-        """
-        try:
-            f = codecs.open(self.__filename, 'r')
-            try:
-                count = 0
-                for line in f:
-                    count += 1
-                return count
-            finally:
-                f.close()
-        except (OSError, IOError), err:
-            if err.errno == errno.ENOENT:
-                return 0
-            raise
-
-    def date(self):
-        """ Return timestamp of log file in usecs """
-        try:
-            mtime = os.path.getmtime(self.__filename)            
-        except OSError, err:
-            if err.errno == errno.ENOENT:
-                # This can happen on fresh wiki when building the index
-                # Usually the first request will create an event log
-                raise LogMissing(str(err))
-            raise
-        return wikiutil.timestamp2version(mtime)
-
-    def peek(self, lines):
-        """ What does this method do?
-
-        @param lines: number of lines, may be negative to move backward 
-            moves file position by lines.
-        @return: True if moving more than (WHAT?) to the beginning and moving
-            to the end or beyond
-        @rtype: boolean
-        peek adjusts .__lineno if set
-        This function is not aware of filters!
-        """
-        self.__rel_index = self.__rel_index + lines
-        while self.__rel_index < 0:
-            if self.__buffer == self.__buffer2:
-                # change to buffer 1
-                self.__buffer = self.__buffer1
-                self.__rel_index = self.__rel_index + self.__buffer.len
-            else:
-                if self.__buffer.offsets[0] == 0:
-                    # already at the beginning of the file
-                    # XXX
-                    self.__rel_index = 0
-                    self.__lineno = 0
-                    return True
-                else:
-                    # load previous lines
-                    self.__buffer2 = self.__buffer1
-                    self.__buffer1 = LineBuffer(self._input,
-                                                self.__buffer2.offsets[0],
-                                                self.buffer_size,
-                                                forward=False)
-                    self.__rel_index = (self.__rel_index +
-                                        self.__buffer1.len)
-                    self.__buffer = self.__buffer1
-                
-        while self.__rel_index >= self.__buffer.len:
-            if self.__buffer == self.__buffer1:
-                # change to buffer 2
-                self.__rel_index = self.__rel_index - self.__buffer.len
-                self.__buffer = self.__buffer2
-            else:
-                # try to load next buffer
-                tmpbuff = LineBuffer(self._input,
-                                     self.__buffer1.offsets[-1],
-                                     self.buffer_size)
-                if tmpbuff.len==0:
-                    # end of file
-                    if self.__lineno:
-                        self.__lineno = (self.__lineno + lines -
-                                         (self.__rel_index -
-                                          len(self.__buffer.offsets)))
-                    self.__rel_index = len(self.__buffer.offsets)
-                    return True
-                # shift buffers
-                self.__buffer1 = self.__buffer2
-                self.__buffer2 = tmpbuff                
-                self.__rel_index = self.__rel_index - self.__buffer1.len
-        if self.__lineno: self.__lineno += lines
-        return False
-
-    def __next(self):
-        """get next line already parsed"""
-        if self.peek(0):
-            raise StopIteration
-        result = self.parser(self.__buffer.lines[self.__rel_index])
-        self.peek(1)
-        return result
-
-    def next(self):
-        """
-        @return: next entry
-        raises StopIteration at file end
-        XXX It does not raise anything!
-        """
-        result = None
-        while result == None:
-            while result == None:
-                result = self.__next()
-            if self.filter and not self.filter(result):
-                result = None
-        return result
-    
-    def __previous(self):
-        if self.peek(-1): raise StopIteration
-        return self.parser(self.__buffer.lines[self.__rel_index])
-
-    def previous(self):
-        """
-        @return: previous entry and moves file position one line back
-        raises StopIteration at file begin
-        """
-        result = None
-        while result == None:
-            while result == None:
-                result = self.__previous()
-            if self.filter and not self.filter(result):
-                result = None
-        return result
-
-    def to_begin(self):
-        """moves file position to the begin"""
-        if self.__buffer1.offsets[0] != 0:
-            self.__buffer1 = LineBuffer(self._input,
-                                        0,
-                                        self.buffer_size)
-            self.__buffer2 = LineBuffer(self._input,
-                                        self.__buffer1.offsets[-1],
-                                        self.buffer_size)
-        self.__buffer = self.__buffer1
-        self.__rel_index = 0
-        self.__lineno = 0
-
-    def to_end(self):
-        """moves file position to the end"""
-        self._input.seek(0, 2) # to end of file
-        size = self._input.tell()
-        if (not self.__buffer2) or (size>self.__buffer2.offsets[-1]):
-            self.__buffer2 = LineBuffer(self._input,
-                                        size,
-                                        self.buffer_size,
-                                        forward = False)
-            
-            self.__buffer1 = LineBuffer(self._input,
-                                        self.__buffer2.offsets[0],
-                                        self.buffer_size,
-                                        forward = False)
-        self.__buffer = self.__buffer2
-        self.__rel_index = self.__buffer2.len
-        self.__lineno = None
-
-    def position(self):
-        """ Return the current file position
-        
-        This can be converted into a String using back-ticks and then
-        be rebuild.
-        For this plain file implementation position is an Integer.
-        """
-        return self.__buffer.offsets[self.__rel_index]
-        
-    def seek(self, position, line_no=None):
-        """ moves file position to an value formerly gotten from .position().
-        To enable line counting line_no must be provided.
-        .seek is much more efficient for moving long distances than .peek.
-        raises ValueError if position is invalid
-        """
-        if self.__buffer1.offsets[0] <= position < self.__buffer1.offsets[-1]:
-            # position is in .__buffer1 
-            self.__rel_index = self.__buffer1.offsets.index(position)
-            self.__buffer = self.__buffer1
-        elif (self.__buffer2.offsets[0] <= position <
-              self.__buffer2.offsets[-1]):
-            # position is in .__buffer2
-            self.__rel_index = self.__buffer2.offsets.index(position)
-            self.__buffer = self.__buffer2
-        else:
-            # load buffers around position
-            self.__buffer1 = LineBuffer(self._input,
-                                        position,
-                                        self.buffer_size,
-                                        forward = False)
-            self.__buffer2 = LineBuffer(self._input,
-                                        position,
-                                        self.buffer_size)
-            self.__buffer = self.__buffer2
-            self.__rel_index = 0
-            # XXX test for valid position
-        self.__lineno = line_no
-
-    def line_no(self):
-        """@return: the current line number or None if line number is unknown"""
-        return self.__lineno
-    
-    def calculate_line_no(self):
-        """ Calculate the current line number from buffer offsets
-        
-        If line number is unknown it is calculated by parsing the whole file.
-        This may be expensive.
-        """
-        self._input.seek(0, 0)
-        lines = self._input.read(self.__buffer.offsets[self.__rel_index])
-        self.__lineno = len(lines.splitlines())
-        return self.__lineno
-
-    def parser(self, line):
-        """
-        @param line: line as read from file
-        @return: parsed line or None on error
-        Converts the line from file to program representation
-        This implementation uses TAB separated strings.
-        This method should be overwritten by the sub classes.
-        """
-        return line.split("\t")
-
-    def add(self, *data):
-        """
-        add line to log file
-        This implementation save the values as TAB separated strings.
-        This method should be overwritten by the sub classes.
-        """
-        line = "\t".join(data)
-        self._add(line)
-        
-    def _add(self, line):
-        """
-        @param line: flat line
-        @type line: String
-        write on entry in the log file
-        """
-        if line != None:
-            if line[-1] != '\n':
-                line += '\n'
-            self._output.write(line)
-
--- a/MoinMoin/macro/PageHits.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/macro/PageHits.py	Wed Jun 07 09:44:08 2006 +0200
@@ -15,9 +15,9 @@
 # Set pickle protocol, see http://docs.python.org/lib/node64.html
 PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
 
-from MoinMoin import caching, config
+from MoinMoin import caching, config, logfile
 from MoinMoin.Page import Page
-from MoinMoin.logfile import eventlog, logfile
+from MoinMoin.logfile import eventlog
 
 
 class PageHits:
--- a/MoinMoin/stats/hitcounts.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/stats/hitcounts.py	Wed Jun 07 09:44:08 2006 +0200
@@ -14,9 +14,9 @@
 
 _debug = 0
 
-from MoinMoin import caching, config, wikiutil
+from MoinMoin import caching, config, wikiutil, logfile
 from MoinMoin.Page import Page
-from MoinMoin.logfile import eventlog, logfile
+from MoinMoin.logfile import eventlog
 
 
 def linkto(pagename, request, params=''):
--- a/MoinMoin/stats/useragents.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/stats/useragents.py	Wed Jun 07 09:44:08 2006 +0200
@@ -13,9 +13,9 @@
 
 _debug = 0
 
-from MoinMoin import wikiutil, caching 
+from MoinMoin import wikiutil, caching, logfile 
 from MoinMoin.Page import Page
-from MoinMoin.logfile import eventlog, logfile
+from MoinMoin.logfile import eventlog
 
 
 def linkto(pagename, request, params=''):
--- a/MoinMoin/wikidicts.py	Tue Jun 06 23:07:08 2006 +0200
+++ b/MoinMoin/wikidicts.py	Wed Jun 07 09:44:08 2006 +0200
@@ -21,9 +21,8 @@
 # Set pickle protocol, see http://docs.python.org/lib/node64.html
 PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
  
-from MoinMoin import config, caching, wikiutil, Page
+from MoinMoin import config, caching, wikiutil, Page, logfile
 from MoinMoin.logfile.editlog import EditLog
-from MoinMoin.logfile import logfile
 
 # Version of the internal data structure which is pickled
 # Please increment if you have changed the structure
--- a/docs/CHANGES	Tue Jun 06 23:07:08 2006 +0200
+++ b/docs/CHANGES	Wed Jun 07 09:44:08 2006 +0200
@@ -61,6 +61,7 @@
       moved util/autoadmin.py to security/autoadmin.py,
       moved security.py to security/__init__.py,
       moved wikiacl.py to security/__init__.py.
+    * moved logfile/logfile.py to logfile/__init__.py
     * added wikiutil.MimeType class (works internally with sanitized mime
       types because the official ones suck)
     * renamed parsers to module names representing sane mimetypes, e.g.: