Skip to content

Commit

Permalink
feat: first
Browse files Browse the repository at this point in the history
Signed-off-by: Carlos Alexandro Becker <[email protected]>
  • Loading branch information
caarlos0 committed Apr 5, 2021
0 parents commit 683b3e6
Show file tree
Hide file tree
Showing 9 changed files with 721 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [caarlos0]
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bin/
dist/
coverage.out
77 changes: 77 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
before:
hooks:
- go mod tidy
gomod:
proxy: true
build:
goarch:
- amd64
- arm64
env:
- CGO_ENABLED=0
nfpms:
- vendor: Becker Software LTDA
homepage: https://carlosbecker.com
maintainer: Carlos Becker <[email protected]>
description: Exports Speedtest results to the Prometheus format
formats:
- deb
- apk
- rpm
dependencies:
- speedtest-cli
brews:
- tap:
owner: caarlos0
name: homebrew-tap
folder: Formula
description: Exports Speedtest results to the Prometheus format
checksum:
name_template: '{{ .ProjectName }}_checksums.txt'
archives:
- name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'
dockers:
- image_templates:
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
- 'caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
dockerfile: Dockerfile
use_buildx: true
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source=https://github.com/caarlos0/speedtest-exporter"
- "--platform=linux/amd64"
- image_templates:
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
- 'caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
dockerfile: Dockerfile
use_buildx: true
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source=https://github.com/caarlos0/speedtest-exporter"
- "--platform=linux/arm64"
goarch: arm64
docker_manifests:
- name_template: 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}'
image_templates:
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
- name_template: 'ghcr.io/caarlos0/speedtest-exporter:latest'
image_templates:
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
- 'ghcr.io/caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
- name_template: 'caarlos0/speedtest-exporter:{{ .Tag }}'
image_templates:
- 'caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
- 'caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
- name_template: 'caarlos0/speedtest-exporter:latest'
image_templates:
- 'caarlos0/speedtest-exporter:{{ .Tag }}-amd64'
- 'caarlos0/speedtest-exporter:{{ .Tag }}-arm64'
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM alpine
EXPOSE 9876
WORKDIR /
COPY speedtest-exporter*.apk /tmp
RUN apk add --allow-untrusted /tmp/speedtest-exporter*.apk
ENTRYPOINT ["/usr/local/bin/speedtest-exporter"]
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# speedtest-exporter

Exports speedtest-cli metrics in the prometheus format.
153 changes: 153 additions & 0 deletions collector/speedtest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package collector

import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"sync"
"time"

"github.com/patrickmn/go-cache"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
)

type speedtestCollector struct {
mutex sync.Mutex
cache *cache.Cache

up *prometheus.Desc
scrapeDuration *prometheus.Desc
pingSeconds *prometheus.Desc
downloadSpeedBytes *prometheus.Desc
uploadSpeedBytes *prometheus.Desc
downloadedBytes *prometheus.Desc
uploadedBytes *prometheus.Desc
}

// NewSpeedtestCollector returns a releases collector
func NewSpeedtestCollector(cache *cache.Cache) prometheus.Collector {
const namespace = "speedtest"
const subsystem = ""
return &speedtestCollector{
cache: cache,
up: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "up"),
"Exporter is being able to talk with GitHub API",
nil,
nil,
),
scrapeDuration: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "scrape_duration_seconds"),
"Returns how long the probe took to complete in seconds",
nil,
nil,
),
pingSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "ping_seconds"),
"Latency",
nil,
nil,
),
downloadSpeedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "download_speed_bytes"),
"Download speed",
nil,
nil,
),
uploadSpeedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "upload_speed_bytes"),
"Upload speed",
nil,
nil,
),
downloadedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "downloaded_bytes"),
"Downloaded bytes",
nil,
nil,
),
uploadedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "uploaded_bytes"),
"Uploaded bytes",
nil,
nil,
),
}
}

// Describe all metrics
func (c *speedtestCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.up
ch <- c.scrapeDuration
ch <- c.pingSeconds
ch <- c.downloadSpeedBytes
ch <- c.uploadSpeedBytes
ch <- c.downloadedBytes
ch <- c.uploadedBytes
}

// Collect all metrics
func (c *speedtestCollector) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock()
defer c.mutex.Unlock()

start := time.Now()
success := 1
defer func() {
ch <- prometheus.MustNewConstMetric(c.scrapeDuration, prometheus.GaugeValue, time.Since(start).Seconds())
ch <- prometheus.MustNewConstMetric(c.up, prometheus.GaugeValue, float64(success))
}()

result, err := c.cachedOrCollect()
if err != nil {
success = 0
log.Errorf("failed to collect: %s", err.Error())
}

ch <- prometheus.MustNewConstMetric(c.downloadSpeedBytes, prometheus.GaugeValue, result.Download)
ch <- prometheus.MustNewConstMetric(c.uploadSpeedBytes, prometheus.GaugeValue, result.Upload)
ch <- prometheus.MustNewConstMetric(c.pingSeconds, prometheus.GaugeValue, result.Ping/1000)
ch <- prometheus.MustNewConstMetric(c.uploadedBytes, prometheus.GaugeValue, result.BytesSent)
ch <- prometheus.MustNewConstMetric(c.downloadedBytes, prometheus.GaugeValue, result.BytesReceived)
}

func (c *speedtestCollector) cachedOrCollect() (SpeedtestResult, error) {
cold, ok := c.cache.Get("result")
if ok {
log.Debug("returning results from cache")
return cold.(SpeedtestResult), nil
}

hot, err := c.collect()
if err != nil {
return hot, err
}
c.cache.Set("result", hot, cache.DefaultExpiration)
return hot, nil
}

func (c *speedtestCollector) collect() (SpeedtestResult, error) {
log.Debug("running speedtest-cli")
var out bytes.Buffer
cmd := exec.Command("speedtest-cli", "--json")
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return SpeedtestResult{}, fmt.Errorf("speedtest-cli failed: %w", err)
}
log.Debug("speedtest-cli result: " + out.String())
var result SpeedtestResult
if err := json.Unmarshal(out.Bytes(), &result); err != nil {
return SpeedtestResult{}, fmt.Errorf("failed to decode speedtest-cli output: %w", err)
}
return result, nil
}

type SpeedtestResult struct {
Download float64 `json:"download"`
Upload float64 `json:"upload"`
Ping float64 `json:"ping"`
BytesSent float64 `json:"bytes_sent"`
BytesReceived float64 `json:"bytes_received"`
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/caarlos0/speedtest-exporter

require (
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.8.0
github.com/prometheus/common v0.15.0
)

go 1.16
Loading

0 comments on commit 683b3e6

Please sign in to comment.