Skip to content

Instantly share code, notes, and snippets.

@fragtion
Created September 14, 2025 14:59
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
"""
ifstat.py — WSL1 network traffic monitor (via Windows PowerShell)
WSL1 does not report interface stats properly via ifconfig or ifstat.
This script mimics the behavior of `ifstat` by displaying per-interface
network I/O statistics (KB/s in and KB/s out) updated once per second.
It leverages a persistent PowerShell process to poll `Get-Counter` once per second.
Credits: https://github.com/fragtion
"""
import subprocess
import time
import sys
import json
import textwrap
def powershell_stream():
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", "-Command", ps_cmd],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
bufsize=1
)
def parse_stats(line):
try:
data = json.loads(line.strip())
if isinstance(data, dict):
data = [data]
stats = {}
for entry in data:
adapter = entry["Name"]
received = int(entry["ReceivedBytes"])
sent = int(entry["SentBytes"])
stats[adapter] = (received, sent)
return stats
except Exception:
return {}
proc = powershell_stream()
# wait for first sample
first_line = proc.stdout.readline()
prev_stats = parse_stats(first_line)
if not prev_stats:
print("No adapters found or error occurred.")
proc.terminate()
sys.exit(1)
adapters = list(prev_stats.keys())
col_width = 10
label_width = col_width * 2
wrapped_names = []
max_lines = 0
for adapter in adapters:
wrapped = textwrap.wrap(adapter, label_width)
wrapped_names.append(wrapped)
if len(wrapped) > max_lines:
max_lines = len(wrapped)
print("Starting network traffic monitoring. Press Ctrl+C to stop.")
print("Note: First sample is baseline. Rates start from second sample.\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()
try:
for line in proc.stdout:
current_stats = parse_stats(line)
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_received, prev_sent = prev_stats[adapter]
curr_received, curr_sent = current_stats[adapter]
delta_received = (curr_received - prev_received) / delta_time / 1024
delta_sent = (curr_sent - prev_sent) / delta_time / 1024
rx_str = f"{delta_received:>{col_width}.2f}"
tx_str = f"{delta_sent:>{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:
proc.terminate()
print("\nMonitoring stopped.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment