The internet drops out for a minute, a video call freezes, a game lags, and by the time you open a Command Prompt it is fine again. You ring your ISP and they run a line test, which passes, because the line is working while they test it. What you need is a record: every few seconds, for hours, how long a reply took and whether one came back at all, with the time against each one.
This article shows how to collect that record with a ping logger, what to ping so the log tells you where the problem is, and how to turn the log into a graph in Excel. It also looks at the Windows API doing the pinging, because two of its defaults are not what the documentation says.
Checked on Windows 10 Pro 22H2 in November 2026.
ping -t 8.8.8.8 pings until you stop it, but each line has no time on it, so a burst of Request timed out cannot be matched to the moment the call dropped. Redirecting it to a file with > does not add times either, and the totals only appear when you press Ctrl+C. It is fine for watching a connection while you fiddle with it, not for leaving overnight.
If you want a quick log with nothing to download, Windows PowerShell 5.1 can do it in one line. It writes the time and the reply in milliseconds every 15 seconds, and leaves the reply blank when nothing came back:
while ($true) { $r = Test-Connection 8.8.8.8 -Count 1 -ErrorAction SilentlyContinue
'{0:yyyy-MM-dd HH:mm:ss},{1}' -f (Get-Date), $r.ResponseTime | Add-Content ping.csv
Start-Sleep 15 }
That covers the basic case. A dedicated tool earns its place when you want several pings per sample averaged, a count of how many were lost, a fixed schedule however long the pings take, a larger packet size, or a run that stops by itself after a set number of hours.
Ping_Log is our free command line tool for exactly this. It sends a cluster of pings at a fixed interval and writes one line per cluster to a CSV file:
Ping_Log [Options] Address
/Cnn = Ping nn times in a Cluster (default 1)
/CAnn = Ping nn times in a Cluster and log the Average
/Rnn = Start a Cluster every nn seconds (default 5)
/Fnn = For nn hours (default until Enter is pressed)
/Bnn = Buffer Size in bytes (default 32)
/S = Silent Mode (default Verbose)
/Oxx = Output to File xx (default none)
The log has a header row and three columns:
Time,Response_Ms,Lost
"2026-11-07 09:14:47",31,0
"2026-11-07 09:15:02",22,0
"2026-11-07 09:15:17",,4
A 0 is a real reply in under a millisecond, which is normal for a router on your own network, so a blank and a zero never mean the same thing. Each line is written as soon as its cluster finishes, so the log survives a crash or a power cut up to the last sample.
A single log tells you the connection dropped. Two logs side by side tell you which part of it dropped. Run one against your own router and one against a reliable address out on the internet, at the same time:
Ping_Log /ca4 /r15 /f12 /oRouter.csv 192.168.1.1
Ping_Log /ca4 /r15 /f12 /oInternet.csv 8.8.8.8
Each sends 4 pings every 15 seconds for 12 hours and logs their average and how many were
lost.Then read them together:
Pinging a single address can mislead if that address has a problem of its own, so for a long dispute with an ISP run a third log against a different provider, such as 1.1.1.1. Busy public servers may also answer pings at a lower priority than real traffic, so an occasional single lost ping is not a fault; what matters is several in a row.
If the connection drops only under load, or a VPN or game misbehaves while ordinary web pages work, repeat the run with larger packets, for example /b1400. A link that handles 32-byte pings but loses big ones points to a marginal line or a packet size problem.
For the numbers your ISP will ask for, =AVERAGE(B:B) and =MAX(B:B) give the average and worst reply times, =SUM(C:C) the pings lost, and =COUNTBLANK(B2:B2881) the samples where nothing came back at all.
Ping_Log does not run ping.exe or open a raw socket. It asks Windows Management Instrumentation (WMI) to do the ping, through the Win32_PingStatus class. A ping is a WQL query, and the reply comes back as the single row it returns:
SELECT * FROM Win32_PingStatus
WHERE Address='8.8.8.8' AND BufferSize=32 AND Timeout=4000
In Delphi that is a few lines of COM, connecting once at the start and running the query once for every ping:
Locator := CreateOleObject ('WbemScripting.SWbemLocator');
WMI_Service := Locator.ConnectServer ('localhost', 'root\CIMV2', '', '');
Replies := WMI_Service.ExecQuery (Format (fmt_WMI_Query,
[QuotedStr (Address), Buffer_Size, Ping_Timeout_Ms]), 'WQL', 0);
Enum := IUnknown (Replies._NewEnum) as IEnumVariant;
if Enum.Next (1, Reply, Fetched) = S_OK
then if Reply.StatusCode = 0
then Record_Reply (Reply.ResponseTime);
The properties that matter are:
Two details are easy to get wrong:
Why use WMI rather than IcmpSendEcho from iphlpapi.dll, the API ping.exe itself uses? WMI needs no administrator rights, takes a host name, an IPv4 or an IPv6 address in the same field, and is available from any language that can talk to COM, including a script. The cost is overhead: each ping is a query through the WMI service, a few milliseconds of extra work for the PC, though not added to the reply time. At one cluster every few seconds that does not matter; for hundreds of pings a second, IcmpSendEcho is the better choice.
It is also what Windows PowerShell 5.1 uses. Test-Connection there is a wrapper around Win32_PingStatus and hands back the same objects, which is why the one-liner earlier reads ResponseTime. PowerShell 7 rewrote Test-Connection on the .NET Ping class, so the property names differ there.
Please chip in if helpful