~jconti/recent-notifications/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""
logtracker.py
by Jason Conti
February 15, 2010

Tracks a log file for changes.
"""

import os
import os.path
import pyinotify
import time

class LogTracker(pyinotify.ProcessEvent):
  """Tracks a log file for changes."""
  def __init__(self, path):
    pyinotify.ProcessEvent.__init__(self)

    self._path = os.path.abspath(path)
    self._offset = self._get_file_length()

    self._listeners = set()

  def add_listener(self, f):
    """A listener is a function of a single argument, the text appended to
    the log when it changed."""
    self._listeners.add(f)

  def remove_listener(self, f):
    """Removes f from the set of listeners."""
    self._listeners.remove(f)

  def start(self):
    """Starts watching the file."""
    self._wm = pyinotify.WatchManager()
    self._wdd = self._wm.add_watch(self._path, pyinotify.IN_MODIFY)
    self._notifier = pyinotify.ThreadedNotifier(self._wm, self)
    self._notifier.start()

  def stop(self):
    """Removes the watch from the tracked file and stops the notifier."""
    self._wm.rm_watch(self._wdd.values())
    self._notifier.stop()

  def _get_file_length(self):
    """Returns the length of the tracked file, returns 0 if there is an error,
    assuming that the file may not have been created yet."""
    try:
      f = open(self._path, "r")
      f.seek(0, os.SEEK_END)
      size = f.tell()
      f.close()
      return size
    except:
      return 0

  def _read_appended_text(self):
    """Opens the tracked file, seeks to the last read offset, reads to EOF
    and updates the last read offset."""
    f = open(self._path, "r")
    f.seek(self._offset, os.SEEK_SET)
    text = f.read()
    self._offset = f.tell()
    f.close()
    return text

  def process_IN_MODIFY(self, event):
    """Reads the appended text in the tracked file and sends it to the listeners."""
    text = self._read_appended_text()
    for f in self._listeners:
      f(text)

def test1(text):
  print "test1:"
  print text

def test2(text):
  print "test2:"
  print text

def main():
  track = LogTracker("test.log")
  track.add_listener(test1)
  track.add_listener(test2)

  while True:
    try:
      time.sleep(10000)
    except:
      track.stop()
      break

if __name__ == '__main__':
  main()