DEV Community

Cover image for SPEEDTEST
Brian Oiko
Brian Oiko

Posted on

SPEEDTEST

Automating Internet Speed Tests with Go: A Practical Project for Developers

Monitoring your internet speed over time is useful for developers, network engineers, and anyone who wants to verify ISP consistency or diagnose connectivity issues. In this post, we'll build a Go program that automates internet speed testing using the speedtest-go library. It logs results in a CSV file every 10 seconds and prints real-time results to the terminal.
Why Build a Speed Test Tool?

There are many browser-based tools for checking internet speed, but few offer automation, logging, and programmatic control. This project is ideal if you want to:

Collect long-term data on download/upload speeds and latency

Monitor your home or office network

Create alerts for slowdowns

Run tests on edge devices like Raspberry Pi
Enter fullscreen mode Exit fullscreen mode

Go's efficiency, simplicity, and concurrency make it a perfect choice for this task.
What We'll Build

Our application:
✅ Runs a speed test every 10 seconds
✅ Logs results in a CSV file
✅ Prints metrics to the console
✅ Handles graceful shutdown with Ctrl+C

The final CSV file includes:
Timestamp, Download (Mbps), Upload (Mbps), Latency (ms), Server Name, Server Location
Required Dependencies

You'll need the speedtest-go library for accessing Speedtest.net servers.
sh


go get github.com/showwin/speedtest-go/speedtest

Project Structure

Here's how we'll organize the files:

/speedtest-monitor
├── main.go
└── speed/
└── performance.go

This modular structure separates concerns and makes the code easier to maintain.
main.go — The Core Controller

This file handles setup, scheduling, and safe shutdown:
go

package main

import (
"encoding/csv"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"

"github.com/showwin/speedtest-go/speedtest"
"speed/speed"
Enter fullscreen mode Exit fullscreen mode

)

func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)

file, err := os.OpenFile("speedtest_results.csv", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
    log.Fatalf("Failed to open file: %v", err)
}
defer file.Close()

writer := csv.NewWriter(file)
defer writer.Flush()

fileInfo, err := file.Stat()
if err != nil {
    log.Fatalf("Failed to get file info: %v", err)
}

if fileInfo.Size() == 0 {
    headers := []string{"Timestamp", "Download (Mbps)", "Upload (Mbps)", "Latency (ms)", "Server Name", "Server Location"}
    if err := writer.Write(headers); err != nil {
        log.Fatalf("Failed to write headers: %v", err)
    }
}

signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

_, err = speedtest.FetchUserInfo()
if err != nil {
    log.Fatalf("Error fetching user info: %v", err)
}

serverList, err := speedtest.FetchServers()
if err != nil {
    log.Fatalf("Error fetching servers: %v", err)
}

ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()

fmt.Println("Running speed tests every 10 seconds. Press Ctrl+C to stop.")
fmt.Println("Results will be saved to speedtest_results.csv")
fmt.Println("--------------------------------------------------")

speed.PerformTest(serverList, writer)

for {
    select {
    case <-ticker.C:
        speed.PerformTest(serverList, writer)
    case <-signalChan:
        fmt.Println("\nGracefully shutting down...")
        fmt.Println("Final results saved to speedtest_results.csv")
        return
    }
}
Enter fullscreen mode Exit fullscreen mode

}

speed/performance.go — The Test Logic

This module performs the download, upload, and latency tests:
go

package speed

import (
"encoding/csv"
"fmt"
"log"
"time"

"github.com/showwin/speedtest-go/speedtest"
Enter fullscreen mode Exit fullscreen mode

)

func PerformTest(serverList speedtest.Servers, writer *csv.Writer) {
targets, err := serverList.FindServer([]int{})
if err != nil || len(targets) == 0 {
log.Printf("Error finding server: %v\n", err)
return
}

bestServer := targets[0]

err = bestServer.DownloadTest()
if err != nil {
    log.Printf("Download test failed: %v\n", err)
    return
}

err = bestServer.UploadTest()
if err != nil {
    log.Printf("Upload test failed: %v\n", err)
    return
}

downloadSpeed := bestServer.DLSpeed / 1000000
uploadSpeed := bestServer.ULSpeed / 1000000
latency := float64(bestServer.Latency.Milliseconds())
serverName := bestServer.Name
serverLocation := bestServer.Country

timestamp := time.Now().Format("2006-01-02 15:04:05")
record := []string{
    timestamp,
    fmt.Sprintf("%.2f", downloadSpeed),
    fmt.Sprintf("%.2f", uploadSpeed),
    fmt.Sprintf("%.2f", latency),
    serverName,
    serverLocation,
}

if err := writer.Write(record); err != nil {
    log.Printf("Error writing to CSV: %v\n", err)
}
writer.Flush()

fmt.Printf("\n[%s]\n", timestamp)
fmt.Printf("Server: %s (%s)\n", serverName, serverLocation)
fmt.Printf("Download: %.2f Mbps\n", downloadSpeed)
fmt.Printf("Upload: %.2f Mbps\n", uploadSpeed)
fmt.Printf("Latency: %.2f ms\n", latency)
fmt.Println("--------------------------------------------------")
Enter fullscreen mode Exit fullscreen mode

}

Sample Output

Here's what the console output looks like:

[2025-05-24 12:45:00]
Server: Telecom XYZ (Germany)
Download: 85.62 Mbps
Upload: 23.47 Mbps

Latency: 14.30 ms

And the CSV output:

Timestamp,Download (Mbps),Upload (Mbps),Latency (ms),Server Name,Server Location
2025-05-24 12:45:00,85.62,23.47,14.30,Telecom XYZ,Germany

Graceful Shutdown

Using Go's os/signal package, the app listens for Ctrl+C and safely closes the file, ensuring all results are saved before exiting.
Potential Enhancements

Export to a time-series database like InfluxDB or Prometheus

Create visual dashboards using Grafana

Send alerts via email or Slack on bandwidth drop

Schedule tests with cron instead of a ticker
Enter fullscreen mode Exit fullscreen mode

Conclusion

This project is a practical example of how Go's simplicity and performance make it ideal for automation tasks. You now have a working tool to log and analyze internet speed data programmatically. Feel free to expand it, containerize it, or hook it into your home lab.

Happy coding!
🔗


Top comments (0)