Skip to content

Instantly share code, notes, and snippets.

@fragtion
Last active December 16, 2025 09:04
Show Gist options
  • Select an option

  • Save fragtion/7507ccfc270acef5c1cc7a7ff3ac0943 to your computer and use it in GitHub Desktop.

Select an option

Save fragtion/7507ccfc270acef5c1cc7a7ff3ac0943 to your computer and use it in GitHub Desktop.
ifstat script for WSL1
#!/usr/bin/env python3
"""
Cross-platform network traffic monitor (ifstat style)
- Windows: uses PowerShell `Get-NetAdapterStatistics` (Works on WSL1)
- Linux: reads `/proc/net/dev`
Displays per-interface KB/s in and KB/s out, updated once per second.
"""
import sys
import time
import json
import textwrap
import subprocess
import platform
col_width = 10
label_width = col_width * 2
# -------------------- Platform-specific functions -------------------- #
def powershell_stream():
"""Stream Windows adapter stats via PowerShell"""
ps_cmd = """
while ($true) {
Get-NetAdapterStatistics |
Select-Object Name,ReceivedBytes,SentBytes |
ConvertTo-Json -Compress;
Start-Sleep -Seconds 1
}
"""
return subprocess.Popen(
["/mnt/c/Windows/SysWOW64/WindowsPowerShell/v1.0/powershell.exe"
if platform.system() == "Linux" and "Microsoft" in platform.release()
else "powershell.exe",
"-Command", ps_cmd],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
bufsize=1
)
def parse_stats_windows(line):
try:
data = json.loads(line.strip())
if isinstance(data, dict):
data = [data]
stats = {}
for entry in data:
adapter = entry["Name"]
stats[adapter] = (int(entry["ReceivedBytes"]), int(entry["SentBytes"]))
return stats
except Exception:
return {}
def read_stats_linux():
stats = {}
try:
with open("/proc/net/dev") as f:
for line in f:
if ":" not in line:
continue
iface, data = line.split(":", 1)
iface = iface.strip()
fields = data.split()
stats[iface] = (int(fields[0]), int(fields[8]))
except Exception:
pass
return stats
# -------------------- Initialization -------------------- #
if sys.platform.startswith("win") or ("Microsoft" in platform.release()):
proc = powershell_stream()
first_line = proc.stdout.readline()
prev_stats = parse_stats_windows(first_line)
read_stats = lambda: parse_stats_windows(proc.stdout.readline())
else:
prev_stats = read_stats_linux()
read_stats = read_stats_linux
if not prev_stats:
print("No network interfaces found.")
sys.exit(1)
adapters = list(prev_stats.keys())
# Wrap interface names
wrapped_names = []
max_lines = 0
for adapter in adapters:
wrapped = textwrap.wrap(adapter, label_width)
wrapped_names.append(wrapped)
max_lines = max(max_lines, len(wrapped))
print("Starting network traffic monitoring. Press Ctrl+C to stop.\n")
for line in range(max_lines):
parts = []
for wrapped in wrapped_names:
text = wrapped[line] if line < len(wrapped) else ""
parts.append(f"{text:^{label_width}}")
print(" ".join(parts))
subheader = " ".join(
f"{'KB/s in':>{col_width}}{'KB/s out':>{col_width}}" for _ in adapters
)
print(subheader)
prev_time = time.time()
# -------------------- Monitoring loop -------------------- #
try:
while True:
time.sleep(1)
current_stats = read_stats()
if not current_stats:
continue
current_time = time.time()
delta_time = current_time - prev_time
line_parts = []
for adapter in adapters:
if adapter in current_stats and adapter in prev_stats:
prev_rx, prev_tx = prev_stats[adapter]
curr_rx, curr_tx = current_stats[adapter]
delta_rx = (curr_rx - prev_rx) / delta_time / 1024
delta_tx = (curr_tx - prev_tx) / delta_time / 1024
rx_str = f"{delta_rx:>{col_width}.2f}"
tx_str = f"{delta_tx:>{col_width}.2f}"
line_parts.append(f"{rx_str}{tx_str}")
else:
line_parts.append(f"{'0.00':>{col_width}}{'0.00':>{col_width}}")
print(" ".join(line_parts))
prev_stats = current_stats
prev_time = current_time
except KeyboardInterrupt:
if sys.platform.startswith("win") or ("Microsoft" in platform.release()):
proc.terminate()
print("\nMonitoring stopped.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment