2022-05-24 21:49:47 +08:00
|
|
|
//go:generate ../../../tools/readme_config_includer/generator
|
2021-09-15 05:26:49 +08:00
|
|
|
package internet_speed
|
|
|
|
|
|
|
|
|
|
import (
|
2022-05-24 21:49:47 +08:00
|
|
|
_ "embed"
|
2021-09-15 05:26:49 +08:00
|
|
|
"fmt"
|
2023-02-23 04:40:44 +08:00
|
|
|
"math"
|
2021-10-20 00:42:15 +08:00
|
|
|
"time"
|
2021-09-15 05:26:49 +08:00
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
"github.com/showwin/speedtest-go/speedtest"
|
|
|
|
|
|
2021-09-15 05:26:49 +08:00
|
|
|
"github.com/influxdata/telegraf"
|
2023-02-08 01:52:21 +08:00
|
|
|
"github.com/influxdata/telegraf/filter"
|
2021-09-15 05:26:49 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
|
|
|
)
|
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
//go:embed sample.conf
|
|
|
|
|
var sampleConfig string
|
|
|
|
|
|
2021-09-15 05:26:49 +08:00
|
|
|
// InternetSpeed is used to store configuration values.
|
|
|
|
|
type InternetSpeed struct {
|
2023-02-08 01:52:21 +08:00
|
|
|
ServerIDInclude []string `toml:"server_id_include"`
|
|
|
|
|
ServerIDExclude []string `toml:"server_id_exclude"`
|
|
|
|
|
EnableFileDownload bool `toml:"enable_file_download" deprecated:"1.25.0;use 'memory_saving_mode' instead"`
|
|
|
|
|
MemorySavingMode bool `toml:"memory_saving_mode"`
|
|
|
|
|
Cache bool `toml:"cache"`
|
|
|
|
|
|
|
|
|
|
Log telegraf.Logger `toml:"-"`
|
|
|
|
|
|
|
|
|
|
server *speedtest.Server
|
|
|
|
|
serverFilter filter.Filter
|
2021-09-15 05:26:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const measurement = "internet_speed"
|
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
func (*InternetSpeed) SampleConfig() string {
|
|
|
|
|
return sampleConfig
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 21:24:20 +08:00
|
|
|
func (is *InternetSpeed) Init() error {
|
|
|
|
|
is.MemorySavingMode = is.MemorySavingMode || is.EnableFileDownload
|
|
|
|
|
|
2023-02-08 01:52:21 +08:00
|
|
|
var err error
|
2023-02-23 04:40:44 +08:00
|
|
|
is.serverFilter, err = filter.NewIncludeExcludeFilterDefaults(is.ServerIDInclude, is.ServerIDExclude, false, false)
|
2023-02-08 01:52:21 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("error compiling server ID filters: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 21:24:20 +08:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-15 05:26:49 +08:00
|
|
|
func (is *InternetSpeed) Gather(acc telegraf.Accumulator) error {
|
2023-02-23 04:40:44 +08:00
|
|
|
// if not caching, go find the closest server each time
|
2023-02-08 01:52:21 +08:00
|
|
|
if !is.Cache || is.server == nil {
|
|
|
|
|
if err := is.findClosestServer(); err != nil {
|
|
|
|
|
return fmt.Errorf("unable to find closest server: %w", err)
|
2022-02-02 06:12:24 +08:00
|
|
|
}
|
2021-09-15 05:26:49 +08:00
|
|
|
}
|
2022-02-02 06:12:24 +08:00
|
|
|
|
2023-02-08 01:52:21 +08:00
|
|
|
err := is.server.PingTest()
|
2021-09-15 05:26:49 +08:00
|
|
|
if err != nil {
|
2023-02-08 01:52:21 +08:00
|
|
|
return fmt.Errorf("ping test failed: %w", err)
|
2021-09-15 05:26:49 +08:00
|
|
|
}
|
2023-02-08 01:52:21 +08:00
|
|
|
err = is.server.DownloadTest(is.MemorySavingMode)
|
2021-09-15 05:26:49 +08:00
|
|
|
if err != nil {
|
2023-02-08 01:52:21 +08:00
|
|
|
return fmt.Errorf("download test failed, try `memory_saving_mode = true` if this fails consistently: %w", err)
|
2021-09-15 05:26:49 +08:00
|
|
|
}
|
2023-02-08 01:52:21 +08:00
|
|
|
err = is.server.UploadTest(is.MemorySavingMode)
|
2021-09-15 05:26:49 +08:00
|
|
|
if err != nil {
|
2023-02-08 01:52:21 +08:00
|
|
|
return fmt.Errorf("upload test failed failed, try `memory_saving_mode = true` if this fails consistently: %w", err)
|
2021-09-15 05:26:49 +08:00
|
|
|
}
|
|
|
|
|
|
2023-02-08 01:52:21 +08:00
|
|
|
fields := map[string]any{
|
|
|
|
|
"download": is.server.DLSpeed,
|
|
|
|
|
"upload": is.server.ULSpeed,
|
|
|
|
|
"latency": timeDurationMillisecondToFloat64(is.server.Latency),
|
2023-02-23 04:40:44 +08:00
|
|
|
"jitter": timeDurationMillisecondToFloat64(is.server.Jitter),
|
2023-02-08 01:52:21 +08:00
|
|
|
}
|
|
|
|
|
tags := map[string]string{
|
|
|
|
|
"server_id": is.server.ID,
|
|
|
|
|
"host": is.server.Host,
|
|
|
|
|
}
|
2023-02-23 04:40:44 +08:00
|
|
|
// recycle the detailed data of each test to prevent data backlog
|
|
|
|
|
is.server.Context.Reset()
|
2021-09-15 05:26:49 +08:00
|
|
|
acc.AddFields(measurement, fields, tags)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2022-02-02 06:12:24 +08:00
|
|
|
|
2023-02-08 01:52:21 +08:00
|
|
|
func (is *InternetSpeed) findClosestServer() error {
|
|
|
|
|
user, err := speedtest.FetchUserInfo()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("fetching user info failed: %w", err)
|
|
|
|
|
}
|
|
|
|
|
serverList, err := speedtest.FetchServers(user)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("fetching server list failed: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(serverList) < 1 {
|
|
|
|
|
return fmt.Errorf("no servers found")
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-23 04:40:44 +08:00
|
|
|
// return the first match or the server with the lowest latency
|
|
|
|
|
// when filter mismatch all servers.
|
|
|
|
|
var min int64 = math.MaxInt64
|
|
|
|
|
selectIndex := -1
|
|
|
|
|
for index, server := range serverList {
|
2023-02-08 01:52:21 +08:00
|
|
|
if is.serverFilter.Match(server.ID) {
|
2023-02-23 04:40:44 +08:00
|
|
|
selectIndex = index
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if server.Latency > 0 {
|
|
|
|
|
if min > server.Latency.Milliseconds() {
|
|
|
|
|
min = server.Latency.Milliseconds()
|
|
|
|
|
selectIndex = index
|
|
|
|
|
}
|
2023-02-08 01:52:21 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-23 04:40:44 +08:00
|
|
|
if selectIndex != -1 {
|
|
|
|
|
is.server = serverList[selectIndex]
|
|
|
|
|
is.Log.Debugf("using server %s in %s (%s)\n", is.server.ID, is.server.Name, is.server.Host)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fmt.Errorf("no server set: filter excluded all servers or no available server found")
|
2023-02-08 01:52:21 +08:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 05:26:49 +08:00
|
|
|
func init() {
|
|
|
|
|
inputs.Add("internet_speed", func() telegraf.Input {
|
|
|
|
|
return &InternetSpeed{}
|
|
|
|
|
})
|
|
|
|
|
}
|
2021-10-20 00:42:15 +08:00
|
|
|
|
|
|
|
|
func timeDurationMillisecondToFloat64(d time.Duration) float64 {
|
|
|
|
|
return float64(d) / float64(time.Millisecond)
|
|
|
|
|
}
|