Skip to content

Instantly share code, notes, and snippets.

@justinkinney
Last active November 9, 2015 19:21
Show Gist options
  • Save justinkinney/08dcc019878701e27ebb to your computer and use it in GitHub Desktop.
Save justinkinney/08dcc019878701e27ebb to your computer and use it in GitHub Desktop.
Threaded file watcher
import os
import signal
import sys
import time
import threading
class Daemon(object):
"""A simple class to properly daemonize a process"""
def __init__(self):
self.running = True
def daemonize(self):
signal.signal(signal.SIGTERM, self._terminate)
signal.signal(signal.SIGQUIT, self._terminate)
""" do other daemonize steps (i.e. chdir('/'), setsid(), double-fork, close files, etc.) """
def _terminate(self):
self.running = False
def run(self):
raise (RuntimeError, 'please implement run() in subclass')
class ProcessorDaemon(Daemon):
def run(self):
self.follower = FollowerThread()
self.non_follower = NonFollowerThread()
self.follower.start()
self.non_follower.start()
while self.running:
time.sleep(1)
self.follower.stop()
self.non_follower.stop()
self.follower.join()
self.non_follower.join()
class DaemonThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self._finished = threading.Event()
class NonFollowerThread(DaemonThread):
def run(self):
for line in open('file_to_watch.log'):
if self._finished.is_set():
return
process_line()
class FollowerThread(DaemonThread):
def run(self):
loglines = follow(open('file_to_watch.log'))
for line in loglines:
if self._finished.is_set():
return
process_line()
def follow(target):
"""stolen/modified from @dabeaz: http://www.dabeaz.com/generators/follow.py"""
target.seek(0, 2)
while True:
line = ''
while len(line) == 0 or line[-1] != '\n':
tail = target.readline()
if tail == '':
time.sleep(0.1)
continue
line += tail
yield line
if __name__ == '__main__':
daemon = ProcessorDaemon()
daemon.daemonize()
daemon.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment