Last active
March 30, 2025 12:45
-
-
Save keithrbennett/e37b7473e018b5cfa5d98ee37e8a0789 to your computer and use it in GitHub Desktop.
Python script to monitor and output Internet connection state to console and log file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python -u | |
# This script monitors the internet connection status and logs the changes to a file. | |
# It uses ping or http to check the connection and the platform module to determine the appropriate ping command for the operating system. | |
# The script writes both human-readable output to stdout and machine-readable JSON logs to the specified log file. | |
# Each log entry includes: | |
# - timestamp: ISO format timestamp | |
# - state: Current connection state ("On" or "Off") | |
# - duration: Duration in the previous state | |
# - event: Only present when monitoring stops (value: "monitor_stopped") | |
# The script supports command-line arguments to specify the check interval and log file. | |
# It also handles keyboard interrupts to gracefully stop the monitoring process. | |
# Sample console output: | |
# Internet connection monitor v3.0.1 | |
# Use -h or --help for detailed usage information | |
# Internet connection monitoring started (checking every 1 seconds) | |
# Logging to: internet-monitor.log | |
# Press Ctrl+C to stop monitoring | |
# 2025-03-27 13:12:27 - Internet connection state: On: 00:00:01 | |
# 2025-03-27 13:12:33 - Internet connection state: Off: 00:00:05 | |
# 2025-03-27 13:12:36 - Internet connection state: On: 00:00:02^C | |
# 2025-03-27 13:12:37 - Monitoring stopped - Connection was On for 00:00:02 | |
# Sample log file output: | |
{"timestamp": "2025-03-27T13:12:26.592210", "state": "On", "duration": 0, "event": "monitor_started"} | |
{"timestamp": "2025-03-27T13:12:29.750346", "state": "Off", "duration": 2.23} | |
{"timestamp": "2025-03-27T13:12:34.821500", "state": "On", "duration": 6.07} | |
{"timestamp": "2025-03-27T13:12:37.300495", "state": "On", "duration": 2.48, "event": "monitor_stopped"} | |
import time | |
import datetime | |
import sys | |
import argparse | |
import json | |
import urllib.request | |
import urllib.error | |
def check_internet_connection(): | |
"""Check if there is an active internet connection.""" | |
return check_internet_connection_with_http() | |
def check_internet_connection_with_http(): | |
"""Check if there is an active internet connection using HTTP.""" | |
try: | |
# Use Google's 204 endpoint for a quick connection test | |
urllib.request.urlopen('https://www.google.com/generate_204') | |
return True | |
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, ConnectionResetError): | |
return False | |
def check_internet_connection_with_ping(): | |
"""Check if there is an active internet connection using ping.""" | |
try: | |
# Choose the appropriate ping command based on the operating system | |
if platform.system().lower() == 'windows': | |
ping_count_param = '-n' | |
else: | |
ping_count_param = '-c' | |
# Ping Google's DNS server with timeout | |
subprocess.check_output(['ping', ping_count_param, '1', '8.8.8.8'], | |
stderr=subprocess.STDOUT, | |
universal_newlines=True) | |
return True | |
except (subprocess.CalledProcessError, subprocess.SubprocessError): | |
return False | |
def format_duration(seconds): | |
"""Format duration in seconds to hours, minutes, and seconds.""" | |
hours, remainder = divmod(seconds, 3600) | |
minutes, seconds = divmod(remainder, 60) | |
return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}" | |
def internet_on_off_string(state, prev_state_change_time): | |
curr_time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
clr_to_end_of_line = '\033[K' | |
const_str = f"\r{clr_to_end_of_line}{curr_time_str} - Internet connection state: " | |
elapsed_time = datetime.datetime.now() - prev_state_change_time | |
elapsed_time_str = format_duration(elapsed_time.total_seconds()) | |
if state: | |
var_str = f"On: {elapsed_time_str}" | |
else: | |
var_str = f" Off: {elapsed_time_str}" | |
return const_str + var_str | |
def state_label(state): | |
return "On" if state else "Off" | |
def create_log_entry(current_state, duration=0, event=None): | |
"""Create a log entry dictionary with the given parameters.""" | |
log_entry = { | |
'timestamp': datetime.datetime.now().isoformat(), | |
'state': state_label(current_state), | |
'duration': round(duration, 2) | |
} | |
if event is not None: | |
log_entry['event'] = event | |
return log_entry | |
def write_log_entry(log_file, log_entry): | |
"""Write a log entry to the specified file.""" | |
with open(log_file, 'a') as f: | |
f.write(json.dumps(log_entry) + '\n') | |
def monitor_connection(check_interval=5, log_file='internet-monitor.log'): | |
""" | |
Monitor internet connection and log changes. | |
Args: | |
check_interval: Time in seconds between connection checks | |
log_file: Name of the file to write machine-readable logs | |
""" | |
# Initial check | |
previous_state = check_internet_connection() | |
state_change_time = datetime.datetime.now() | |
# Write initial state to both stdout and log file | |
write_log_entry(log_file, create_log_entry(previous_state, event='monitor_started')) | |
print(internet_on_off_string(previous_state, state_change_time), end='') | |
try: | |
while True: | |
time.sleep(check_interval) | |
current_time = datetime.datetime.now() | |
current_state = check_internet_connection() | |
# If the state has changed | |
if current_state != previous_state: | |
# Write machine-readable log entry | |
duration = (current_time - state_change_time).total_seconds() | |
log_entry = create_log_entry( | |
previous_state, | |
duration | |
) | |
write_log_entry(log_file, log_entry) | |
# Write human-readable output for state changes | |
print(f"\n{internet_on_off_string(current_state, current_time)}", end='') | |
# Update state tracking variables | |
previous_state = current_state | |
state_change_time = current_time | |
else: | |
print(internet_on_off_string(current_state, state_change_time), end='') | |
except KeyboardInterrupt: | |
# Calculate final duration when the program is interrupted | |
current_time = datetime.datetime.now() | |
duration = (current_time - state_change_time).total_seconds() | |
# Write final log entry | |
log_entry = create_log_entry( | |
previous_state, | |
duration=duration, | |
event='monitor_stopped' | |
) | |
write_log_entry(log_file, log_entry) | |
print(f"\n{current_time.strftime('%Y-%m-%d %H:%M:%S')} - " | |
f"Monitoring stopped - Connection was {state_label(current_state)} " | |
f"for {format_duration(duration)}") | |
sys.exit(0) | |
def main(): | |
parser = argparse.ArgumentParser( | |
description='Monitor internet connection status', | |
epilog=""" | |
Examples: | |
./internet_monitor.py -n 10 # Check every 10 seconds | |
./internet_monitor.py -l my-log.json # Use custom log file | |
./internet_monitor.py -n 5 -l log.txt # Combine options | |
The script writes both human-readable output to stdout and machine-readable | |
JSON logs to the specified log file. Each log entry includes: | |
- timestamp: ISO format timestamp | |
- state: Current connection state ("On" or "Off") | |
- duration: Duration in the previous state | |
- event: Only present when monitoring stops (value: "monitor_stopped") | |
""", | |
formatter_class=argparse.RawDescriptionHelpFormatter) | |
parser.add_argument('-n', '--interval', type=float, default=5, | |
help='Check interval in seconds (default: 5)') | |
parser.add_argument('-l', '--log-file', default='internet-monitor.log', | |
help='Name of the log file (default: internet-monitor.log)') | |
args = parser.parse_args() | |
print("Internet connection monitor v3.0.1") | |
print("Use -h or --help for detailed usage information") | |
print(f"Internet connection monitoring started (checking every {args.interval} seconds)") | |
print(f"Logging to: {args.log_file}") | |
print("Press Ctrl+C to stop monitoring") | |
monitor_connection(args.interval, args.log_file) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As a followup to the previous comment, I realized some clarifications to the program's output should be made, and asked the AI assistance to implement them. After about a dozen attempts at the first improvement that resulted in failure, I decided to do it myself, the old fashioned way. It turned out that all that was needed was a minor tweak to a single line of code. I wasted a lot of time expecting the AI to be brilliant, but it was an utter failure. I learned that a really important skill with AI assisted coding is just knowing when and when not to use it at all.