Welcome, guest | Sign In | My Account | Store | Cart

I've seen several tail implementations and they've seemed overly complicated, or overengineered, for my purposes.

Here's an implementation I'm using in my production code, it's _ONLY_ for following an open stream, line by line, and sleeps for a second while waiting for activity. No heuristics, no configurability, it's simple and --in my opinion-- clean enough to understand in a single look.

Enjoy!!

Python, 50 lines
 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
#!/usr/bin/python2.7
# vim:ai:et:ts=4:sw=4:wm=0:encoding=utf8:fileencoding=utf8
"""
tail.py
=======
Exports 'follow', which yields linewise the content being added
to a text file, similar to unix' "tail -f" functionality.

As a demonstration, you can run this script directly with an
argument, the filename you wish to follow. I use it to follow
my httpd logs:

$ python2.7 tail.py /var/log/httpd/access_log
....

"""

__all__ = ('follow',)

import time

def follow(stream):
    "Follow the live contents of a text file."
    line = ''
    for block in iter(lambda:stream.read(1024), None):
        if '\n' in block:
            # Only enter this block if we have at least one line to yield.
            # The +[''] part is to catch the corner case of when a block
            # ends in a newline, in which case it would repeat a line.
            for line in (line+block).splitlines(True)+['']:
                if line.endswith('\n'):
                    yield line
            # When exiting the for loop, 'line' has any remaninig text.
        elif not block:
            # Wait for data.
            time.sleep(1.0)
    # The End.

if __name__ == '__main__':
    # As a simple demonstration, run it with the filename to tail.
    import sys
    with open(sys.argv[1], 'rt') as following:
        following.seek(-64, 2)
        try:
            for line in follow(following):
                sys.stdout.write(line)
        except KeyboardInterrupt:
            pass

# Fin.