-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmultitail_example.py
executable file
·130 lines (108 loc) · 3.75 KB
/
multitail_example.py
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python2
import os
from multiprocessing import Process, Queue
from queue import Empty
import logging
import inotifyx
ADD, REMOVE = 1, 2
log = logging.getLogger('')
class Bidict(dict):
def __setitem__(self, k, v):
dict.__setitem__(self, k, v)
dict.__setitem__(self, v, k)
def __delitem__(self, k):
v = self[k]
dict.__delitem__(self, k)
dict.__delitem__(self, v)
def process_q_names(q_names, fd, watches, open_files):
i = 0
try:
for i, (op, fname) in enumerate(iter(q_names.get_nowait, None)):
if op == ADD:
log.debug('op ADD %s', fname)
if fname in watches:
log.debug('op ADD %s already added', fname)
continue
watch_id = inotifyx.add_watch(fd, fname, inotifyx.IN_MODIFY)
watches[watch_id] = fname
elif op == REMOVE:
log.debug('op REMOVE %s', fname)
watch_id = watches[fname]
if not watch_id:
log.debug('op REMOVE %s already removed', fname)
continue
inotifyx.rm_watch(fd, watch_id)
del watches[watch_id]
open_file = open_files.get(fname)
if open_file:
open_file.close()
del open_files[fname]
except Empty:
pass
finally:
log.debug('processed %d names' % i)
log.debug('watches: %s', watches)
def process_events(fd, watches, open_files):
for event in inotifyx.get_events(fd, 1): # time out after one second
if event.mask & inotifyx.IN_IGNORED:
log.debug('event %s, should be ignored', event)
continue
fname = watches.get(event.wd)
if not fname: # file shouldn't be watched anymore
log.warn('event %s, whats going on?', event)
continue
open_file = open_files.get(fname)
if not open_file:
log.debug('event for %s, opening file', fname)
open_file = open_files[fname] = open(fname)
open_file.seek(0, 2) # seek to end
process_file(open_file, fname)
def process_file(open_file, fname):
log.debug('processing %s', fname)
line = open_file.readline()
while line:
print((fname, line))
line = open_file.readline()
def watch_thread(q_names):
watches = Bidict()
fd = inotifyx.init()
open_files = {}
try:
while True:
process_q_names(q_names, fd, watches, open_files)
process_events(fd, watches, open_files)
finally:
log.debug('watches: %s', watches)
for fname_or_watch_id in watches:
log.debug('cleanup fname_or_watch_id %s', fname_or_watch_id)
if isinstance(fname_or_watch_id, int): # it's a watch_id!
inotifyx.rm_watch(fd, fname_or_watch_id)
for fname, open_file in open_files.items():
log.debug('cleanup open_file %s', fname)
open_file.close()
os.close(fd)
def sigchld_handler(_1, _2):
import sys
log.info("Got SIGCHLD, exiting")
sys.exit()
def main():
from time import sleep
from signal import signal, SIGCHLD
signal(SIGCHLD, sigchld_handler)
q_names = Queue()
q_names.put((ADD, '/var/log/dpkg.log'))
watch = Process(target=watch_thread, args=(q_names,))
watch.daemon = True
watch.start()
while True:
# sleep(0.1)
q_names.put((ADD, '/var/log/dpkg.log'))
q_names.put((ADD, 'log'))
q_names.put((ADD, 'log2'))
sleep(0.1)
if __name__ == '__main__':
logging.basicConfig(
level=logging.DEBUG,
format="%(filename)s:%(lineno)-4s %(levelname)5s %(funcName)s: %(message)s"
)
main()