├── LICENSE.md ├── README.md └── monitor_internet_connection.py /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Released under MIT License (Modified) 2 | 3 | Copyright (c) 2020 Martin Francis O'Connor. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or any portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # monitor internet connection 2 | A Python module to monitor the uptime of the Internet connection in real-time and record the time and duration of any downtime. 3 | 4 | 5 | Sample output 6 | ----------------------------- 7 | 8 | ``` 9 | -------------------------------------------------------------- 10 | -------------------------------------------------------------- 11 | Monitoring Internet Connection commencing : 2020-01-10 10:34:45 polling every 1 second(s) 12 | -------Internet Connection unavailable at : 2020-01-11 07:35:01 13 | -------Internet Connection restored at : 2020-01-11 07:35:10 14 | -------The duration of the downtime was : 0:00:09 15 | -------Internet Connection unavailable at : 2020-01-12 08:35:20 16 | -------Internet Connection restored at : 2020-01-12 08:36:27 17 | -------The duration of the downtime was : 0:01:07 18 | Monitoring Internet Connection stopped at : 2020-01-13 12:42:38 19 | ``` 20 | 21 | 22 | Overview 23 | -------- 24 | Name: monitor_internet_connection 25 | 26 | Version: 1.2.1 27 | 28 | Date: 27th January 2020 29 | 30 | Author: Martin F. O'Connor 31 | 32 | YouTube Channel: [Martin O'Connor](https://www.youtube.com/channel/UCSmYfqnVlhB418ugEZxudQw) 33 | 34 | 35 | What is monitor_internet_connection? 36 | --------------------------------------- 37 | It is a Python module to monitor the uptime of the Internet connection - that is to say to monitor that an external IP address is always reachable. 38 | 39 | 40 | Why should I use monitor_internet_connection? 41 | ------------------------------------------------- 42 | If you have automated long-running processes/programs/activities on your computer that requires Internet connectivity, there is nothing worse than coming back the next hour/day/week/whenever to review the logs/progress and find out that the program(s) failed or data is missing because of lost Internet connectivity. What is worse - you may not know exactly when Internet connectivity was lost. Thus, will you need to rerun the entire program/process? Or just a part of it? and so on. 43 | 44 | The Python module `monitor_internet_connection` is a solution to this problem in that it monitors Internet connectivity in real-time, displaying on the console/terminal and recording to a log file: the start time, the end time and the duration of any Internet connectivity downtime. You may simply run this module in a console/terminal and leave it running for days/weeks on end. 45 | 46 | 47 | What does monitor_internet_connection do? 48 | -------------------------------------------- 49 | Every X seconds (default polling frequency is 1 second), the program monitors whether the Internet connection is alive and an external IP address is reachable. 50 | 51 | If the Internet is unreachable: 52 | 53 | 1) The first observed time of failure is logged. 54 | 55 | 2) Every one-minute interval of subsequent unavailability is logged. The one-minute logs can be useful as a proxy indicator of whether the computer lost power or just the Internet connection was unavailable. 56 | 57 | 3) When Internet connectivity is restored, the first observed time of restoration is logged. 58 | 59 | 4) Finally, the total time duration of the Internet unavailability is logged. 60 | 61 | 62 | 63 | Log File 64 | -------------------------------------------- 65 | 66 | - The log file is called `internet_monitor.log`. 67 | - The log file is written to the current working folder. 68 | - The log file is always appended to, never overwritten. 69 | - The information written to the log file is also displayed on the console/terminal. 70 | 71 | - The log file may be disabled via a command line parameter. See Usage below. 72 | 73 | Prerequisites 74 | ------------- 75 | You must have Python 3.6 or higher installed. 76 | 77 | 78 | Installation 79 | ------------------------------------------------------------------- 80 | 81 | 82 | ```console 83 | pip install monitor_internet_connection 84 | ``` 85 | 86 | 87 | QuickStart 88 | ------------------------------------------------------- 89 | 90 | ```console 91 | python -m monitor_internet_connection 92 | ``` 93 | 94 | 95 | How do I exit the program 96 | ------------------------------------------------------- 97 | To exit the program, simply press `Ctrl-C` inside the console/terminal. This will cause the program to exit gracefully. 98 | 99 | Usage 100 | ------------------------------------------------------- 101 | 102 | ```console 103 | usage: python -m monitor_internet_connection [-h] [-n] [-f N] 104 | 105 | Monitor the uptime of the Internet connection and record any downtime 106 | 107 | optional arguments: 108 | -h, --help show this help message and exit 109 | -n, --no-logfile do not create a log file (default: False) 110 | -f N, --freq N specify polling frequency in seconds (default: 1) 111 | 112 | ``` 113 | 114 | Acknowledgments 115 | --------------- 116 | The `is_internet-alive` method was inspired by 7h3rAm's answer on [Stackoverflow](https://stackoverflow.com/questions/3764291/checking-network-connection) 117 | 118 | 119 | Licence 120 | --------------- 121 | This project is licensed under the MIT License - see the LICENSE.md file for details 122 | -------------------------------------------------------------------------------- /monitor_internet_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Name: monitor_internet_connection.py 3 | Author: Martin F. O'Connor (C) 4 | Description: Monitor Internet connectivity and record time and duration 5 | of any downtime. 6 | 7 | How to run: To run this program from the Console/Terminal, type: 8 | python monitor_internet_connection.py 9 | 10 | Date: 23rd June 2019 11 | Version: 1.0 12 | 13 | This program checks every X (5) seconds whether the Internet connection 14 | is alive and an external IP address is reachable. 15 | If the Internet connection is unavailable: 16 | 1. The first observed time of failure is logged. 17 | 2. Every 1-minute interval of subsequent downtime is logged. 18 | 3. When Internet connectivity is restored, the first observed time of 19 | restoration is logged. 20 | 4. Finally, the total duration of the downtime is logged. 21 | 22 | 23 | Date: 13th January 2020 24 | Version: 1.1 25 | 26 | Added functionality to capture Ctrl-C (and SIGINT) and exit the program 27 | gracefully. 28 | 29 | 30 | Date: 15th January 2020 31 | Version: 1.1.3 32 | 33 | Updates: 34 | 1. Made available as a public package called 'monitor internet connection'. 35 | on the Python Package Index https://pypi.org/ 36 | 37 | 2. Greatly simplified the installation instructions. 38 | To install: pip install monitor_internet_connection 39 | To run: python -m monitor_internet_connection 40 | 41 | 42 | Date: 16th January 2020 43 | Version: 1.2.0 44 | 45 | Updates: 46 | 1. Added the argparse library. 47 | 2. Added command line option to display a help message. 48 | 3. Added command line option to disable the logfile. 49 | With this option, no write-access to disk is required. 50 | 4. Added command line option to specify the polling frequency in seconds. 51 | There are nine options available [1, 2, 3, 4, 5, 10, 20, 30, 60]. 52 | 5. When logfile is enabled, verify logfile can be created 53 | in current working folder. 54 | 55 | Date: 27th January 2020 56 | Version: 1.2.1 57 | 58 | Updates: 59 | 1. Remove return statement to allow network socket to close. 60 | (Thanks to kevin86wright) 61 | """ 62 | 63 | import time 64 | import datetime 65 | import socket 66 | import os 67 | import signal 68 | import argparse 69 | import sys 70 | 71 | # If enabled, the log file will be created in the current working folder. 72 | log_filename = "internet_monitor.log" 73 | file = os.path.join(os.getcwd(), log_filename) 74 | 75 | 76 | def parse_args(args=sys.argv[1:]): 77 | """Parse arguments.""" 78 | 79 | parser = argparse.ArgumentParser( 80 | description="Monitor the uptime of the Internet connection and record any downtime", 81 | prog='python -m monitor_internet_connection') 82 | 83 | parser.add_argument("-n", "--no-logfile", dest='disable_logfile', 84 | help="do not create a logfile", 85 | action="store_true") 86 | 87 | parser.add_argument("-f", "--freq", dest="polling_freq", metavar="N", 88 | default=1, 89 | type=int, 90 | choices=[1, 2, 3, 4, 5, 10, 20, 30, 60], 91 | help="specify polling frequency in seconds") 92 | 93 | return parser.parse_args(args) 94 | 95 | 96 | 97 | def is_internet_alive(host="8.8.8.8", port=53, timeout=3): 98 | """Check if Internet Connection is alive and external IP address is reachable. 99 | 100 | Input Parameters: 101 | host: (string) 8.8.8.8 (google-public-dns-a.google.com) 102 | port: (integer) (53/tcp DNS Service). 103 | timeout: (float) timeout in seconds. 104 | 105 | Returns: 106 | True (Boolean) if external IP address is reachable. 107 | False (Boolean) if external IP address is unreachable. 108 | """ 109 | 110 | try: 111 | socket.setdefaulttimeout(timeout) 112 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 113 | s.connect((host, port)) 114 | except OSError as error: 115 | # print(error.strerror) 116 | return False 117 | else: 118 | s.close() 119 | return True 120 | 121 | 122 | def calc_time_diff(start, end): 123 | """ Calculate duration between two times and return as HH:MM:SS 124 | 125 | Input Params: 126 | start and end times 127 | both datetime objects created from datetime.datetime.now() 128 | 129 | Returns: 130 | The duration (string) in the form HH:MM:SS 131 | """ 132 | 133 | time_difference = end - start 134 | secs = str(time_difference.total_seconds()) 135 | return str(datetime.timedelta(seconds=float(secs))).split(".")[0] 136 | 137 | 138 | def signal_handler(signal_received, frame): 139 | """ Capture Ctrl-C (or SIGINT) and exit the program gracefully. 140 | 141 | Input Params: 142 | signal_received (integer) is the signal number captured and received. 143 | frame (frame object) is the current stack frame. 144 | 145 | Returns: 146 | This method exits the program, thus nothing is returned. 147 | """ 148 | 149 | # Display exit message to console and record in log file. 150 | exit_time = datetime.datetime.now() 151 | exit_msg = "Monitoring Internet Connection stopped at : " + exit_time.strftime("%Y-%m-%d %H:%M:%S") 152 | print(exit_msg) 153 | 154 | if enable_logfile: 155 | with open(file, 'a') as writer: 156 | writer.write(exit_msg + "\n") 157 | 158 | sys.exit() 159 | 160 | 161 | def verify_write_access(): 162 | """ Verify the logfile can be created in the current working folder""" 163 | 164 | if enable_logfile: 165 | try: 166 | with open(file, 'a') as writer: 167 | pass 168 | except OSError as err: 169 | print("Unable to create logfile in current working folder. Exiting program.") 170 | sys.exit() 171 | finally: 172 | pass 173 | 174 | 175 | 176 | def monitor_inet_connection(enable_logfile = True, polling_freq = 1): 177 | """ Monitor internet connection indefinitely.""" 178 | 179 | # Capture the Ctrl-C (or SIGINT) signal to permit the program to exit gracefully. 180 | signal.signal(signal.SIGINT, signal_handler) 181 | 182 | if enable_logfile: 183 | verify_write_access() 184 | 185 | # Write to log file when Internet monitoring commences. 186 | now = datetime.datetime.now() 187 | # msg = "Monitoring Internet Connection commencing: " + now.strftime("%Y-%m-%d %H:%M:%S") 188 | msg = "Monitoring Internet Connection commencing : " + str(now).split(".")[0] + \ 189 | " polling every " + str(polling_freq) + " second(s)" 190 | print(msg) 191 | 192 | if enable_logfile: 193 | with open(file, 'a') as writer: 194 | writer.write("--------------------------------------------------------------\n") 195 | writer.write("--------------------------------------------------------------\n") 196 | writer.write(msg + "\n") 197 | 198 | while True: 199 | # When run on cmd line, exit program via Ctrl-C. 200 | if is_internet_alive(): 201 | time.sleep(polling_freq) 202 | else: 203 | # Record observed time when internet connectivity fails. 204 | fail_time = datetime.datetime.now() 205 | msg = "-------Internet Connection unavailable at : " + str(fail_time).split(".")[0] 206 | print(msg) 207 | if enable_logfile: 208 | with open(file, 'a') as writer: 209 | writer.write(msg + "\n") 210 | 211 | # Check every 1 second to see if internet connectivity restored. 212 | counter = 0 213 | while not is_internet_alive(): 214 | time.sleep(1) 215 | counter += 1 216 | # For each minute of downtime, log it. 217 | # The one-minute logs can be useful as a proxy to indicate whether the computer lost power, 218 | # or just the internet connection was unavailable. 219 | if counter >= 60: 220 | counter = 0 221 | now = datetime.datetime.now() 222 | msg = "-----------Internet Connection still unavailable at : " + str(now).split(".")[0] 223 | print(msg) 224 | if enable_logfile: 225 | with open(file, 'a') as writer: 226 | writer.write(msg + "\n") 227 | 228 | # Record observed time when internet connectivity restored. 229 | restore_time = datetime.datetime.now() 230 | restore_msg = "-------Internet Connection restored at : " + str(restore_time).split(".")[0] 231 | 232 | # Calculate the total duration of the downtime 233 | downtime_duration = calc_time_diff(fail_time, restore_time) 234 | duration_msg = "-------The duration of the downtime was : " + downtime_duration 235 | 236 | # Display restoration message to console and record in log file. 237 | print(restore_msg) 238 | print(duration_msg) 239 | if enable_logfile: 240 | with open(file, 'a') as writer: 241 | writer.write(restore_msg + "\n") 242 | writer.write(duration_msg + "\n") 243 | 244 | 245 | 246 | if __name__ == "__main__": 247 | args = parse_args() 248 | 249 | enable_logfile = not args.disable_logfile 250 | monitor_inet_connection(enable_logfile, args.polling_freq) 251 | 252 | 253 | --------------------------------------------------------------------------------