b2f249cce67e0494465edeae7dd7e5bdae6b50dc
David Blume first commit.

David Blume authored 5 years ago

1) #!/usr/bin/python3
2) #
3) # Since this is meant to be run as a daemon, do not use #!/usr/bin/env python3,
4) # because the process name would then be python3, not based on __FILE__.
5) #
6) # [filename] -d 3 192.168.1.1 192.168.1.12 &
7) # disown [jobid]
8) import os
9) import sys
10) import subprocess
11) import time
12) from argparse import ArgumentParser
13) import threading
14) import queue
15) 
16) 
17) def pinger(host, delay):
18)     """Independent worker thread: repeatedly ping, check, print and sleep."""
19)     last_results = None
20)     while True:
21)         now = time.localtime()
22)         success = ping(host)
23)         if success != last_results:
24)             status = "UP" if success else "DOWN"
25)             _print_queue.put([f'{time.strftime("%Y-%m-%d %H:%M:%S", now)} {host} {status}'])
26)             last_results = success
27)         time.sleep(delay)
28) 
29) 
30) def ping(host):
31)     """Returns True if host (str) responds to a ping request."""
32)     return subprocess.call([*_ping_cmd, host], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
33) 
34) 
35) def print_manager():
36)     """The only thread allowed to write output."""
37)     while True:
38)         job = _print_queue.get()
39)         for line in job:
40)             log(line)
41)         _print_queue.task_done()
42) 
43) 
44) def log(*args, **kwargs):
45)     """Opens the logfile, writes the log, and closes the logfile."""
46)     # I don't leave the log file open for writing because another process needs access too.
47)     with open(_logname, 'a') as fp:
48)         return print(*args, **kwargs, file=fp)
49) 
50) 
51) if __name__ == '__main__':
52)     parser = ArgumentParser(description="Repeatedly ping sites. Ex: %(prog)s -d 3 192.168.1.1 192.168.1.12")
53)     parser.add_argument('-d', '--delay', type=float, default=1.0, help='Delay between pings')
54)     parser.add_argument('addresses', nargs='+', help='Addresses to ping')
55)     parser_args = parser.parse_args()
56) 
57)     _logname = os.path.join(os.path.expanduser('~'), 'log', os.path.basename(sys.argv[0]).replace('py', 'txt'))
58) 
59)     # Choose the ping parameters appropriate for the platform
60)     if sys.platform == 'cygwin' or sys.platform == 'win32':
61)         _ping_cmd = ('ping', '-n', '1', '-w', '2000')
62)     else:
63)         _ping_cmd = ('ping', '-c', '1', '-W', '2', '-q')
64) 
65)     _print_queue = queue.Queue()
66)     print_thread = threading.Thread(target=print_manager, daemon=True)
67)     print_thread.start()
68) 
69)     _print_queue.put([f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}'
70)                       f' PID={os.getpid()} repeat={parser_args.delay}s Starting'])
David Blume Instead of having the proce...

David Blume authored 5 years ago

71) 
72)     # Create worker threads for all but one host address. (Saving one address for this thread.)
73)     for address in parser_args.addresses[:-1]:
David Blume first commit.

David Blume authored 5 years ago

74)         t = threading.Thread(target=pinger, args=(address, parser_args.delay), daemon=True)
75)         t.start()
76)         del t
77)