544bf52764e44ae17a2ba3a2b6956cced0c8ec14
David Blume first commit.

David Blume authored 4 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
David Blume Add notifications for SIGTE...

David Blume authored 4 years ago

15) import signal
16) 
17) 
David Blume Add type hints.

David Blume authored 3 years ago

18) def log_exit(sig: int, frame) -> None:
David Blume Rename a parameter instead...

David Blume authored 4 years ago

19)     _print_queue.put([f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} '
20)                       f'PID={os.getpid()} signal={signal.Signals(sig).name} Exiting.'])
David Blume Add notifications for SIGTE...

David Blume authored 4 years ago

21)     _print_queue.join()
22)     sys.exit(0)
David Blume first commit.

David Blume authored 4 years ago

23) 
24) 
David Blume Add type hints.

David Blume authored 3 years ago

25) def pinger(host: str, delay: float) -> None:
David Blume first commit.

David Blume authored 4 years ago

26)     """Independent worker thread: repeatedly ping, check, print and sleep."""
27)     last_results = None
28)     while True:
29)         now = time.localtime()
30)         success = ping(host)
31)         if success != last_results:
32)             status = "UP" if success else "DOWN"
33)             _print_queue.put([f'{time.strftime("%Y-%m-%d %H:%M:%S", now)} {host} {status}'])
34)             last_results = success
35)         time.sleep(delay)
36) 
37) 
David Blume Add type hints.

David Blume authored 3 years ago

38) def ping(host: str) -> int:
David Blume first commit.

David Blume authored 4 years ago

39)     """Returns True if host (str) responds to a ping request."""
40)     return subprocess.call([*_ping_cmd, host], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
41) 
42) 
David Blume Add type hints.

David Blume authored 3 years ago

43) def print_manager() -> None:
David Blume first commit.

David Blume authored 4 years ago

44)     """The only thread allowed to write output."""
45)     while True:
46)         job = _print_queue.get()
47)         for line in job:
48)             log(line)
49)         _print_queue.task_done()
50) 
51) 
David Blume Add type hints.

David Blume authored 3 years ago

52) def log(*args, **kwargs) -> None:
David Blume first commit.

David Blume authored 4 years ago

53)     """Opens the logfile, writes the log, and closes the logfile."""
54)     # I don't leave the log file open for writing because another process needs access too.
55)     with open(_logname, 'a') as fp:
David Blume Add type hints.

David Blume authored 3 years ago

56)         print(*args, **kwargs, file=fp)
David Blume first commit.

David Blume authored 4 years ago

57) 
58) 
59) if __name__ == '__main__':
60)     parser = ArgumentParser(description="Repeatedly ping sites. Ex: %(prog)s -d 3 192.168.1.1 192.168.1.12")
David Blume Add notifications for SIGTE...

David Blume authored 4 years ago

61)     parser.add_argument('-d', '--delay', type=float, default=3.0, help='Delay between pings')
David Blume first commit.

David Blume authored 4 years ago

62)     parser.add_argument('addresses', nargs='+', help='Addresses to ping')
63)     parser_args = parser.parse_args()
64) 
65)     _logname = os.path.join(os.path.expanduser('~'), 'log', os.path.basename(sys.argv[0]).replace('py', 'txt'))
66) 
67)     # Choose the ping parameters appropriate for the platform
68)     if sys.platform == 'cygwin' or sys.platform == 'win32':
69)         _ping_cmd = ('ping', '-n', '1', '-w', '2000')
70)     else:
71)         _ping_cmd = ('ping', '-c', '1', '-W', '2', '-q')
72) 
73)     _print_queue = queue.Queue()
74)     print_thread = threading.Thread(target=print_manager, daemon=True)
75)     print_thread.start()
76) 
David Blume Add notifications for SIGTE...

David Blume authored 4 years ago

77)     _print_queue.put([f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} PID={os.getpid()}'
78)         f' repeat={parser_args.delay}s addresses={",".join(parser_args.addresses)} Starting'])
79) 
80)     signal.signal(signal.SIGINT, log_exit)
81)     signal.signal(signal.SIGTERM, log_exit)
David Blume Instead of having the proce...

David Blume authored 4 years ago

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

David Blume authored 4 years ago

85)         t = threading.Thread(target=pinger, args=(address, parser_args.delay), daemon=True)
86)         t.start()
87)         del t
88)