wip: poc
This commit is contained in:
parent
13d4df3e3a
commit
6e46013a9a
|
@ -0,0 +1,15 @@
|
|||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{json,yaml}]
|
||||
indent_size = 2
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus
|
||||
ports:
|
||||
- 9090:9090
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
grafana:
|
||||
image: grafana/grafana
|
||||
ports:
|
||||
- 3000:3000
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
targets:
|
||||
- name: Home
|
||||
url: https://aireone.xyz
|
||||
interval: 2
|
||||
- name: Gitea
|
||||
url: https://gitea.aireone.xyz
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"words": [
|
||||
"gocron",
|
||||
"labtime",
|
||||
"promhttp"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
module aireone.xyz/labtime
|
||||
|
||||
go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/go-co-op/gocron/v2 v2.11.0
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.4.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
)
|
|
@ -0,0 +1,31 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/go-co-op/gocron/v2 v2.11.0 h1:IOowNA6SzwdRFnD4/Ol3Kj6G2xKfsoiiGq2Jhhm9bvE=
|
||||
github.com/go-co-op/gocron/v2 v2.11.0/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,173 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// List of targets to ping
|
||||
Targets []struct {
|
||||
// Name of the target. Used to identify the target from Prometheus.
|
||||
Name string `yaml:"name"`
|
||||
// URL of the target. The target should be accessible from the machine running the exporter. The URL should contain the protocol (http:// or https://) and the port if it's not the default one.
|
||||
Url string `yaml:"url"`
|
||||
// Interval to ping the target. Default is 5 seconds
|
||||
Interval int `yaml:"interval,omitempty"`
|
||||
} `yaml:"targets"`
|
||||
}
|
||||
|
||||
func NewConfig(configPath string) (*Config, error) {
|
||||
// Create config structure
|
||||
config := &Config{}
|
||||
|
||||
// Open config file
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Init new YAML decode
|
||||
d := yaml.NewDecoder(file)
|
||||
|
||||
// Start YAML decoding from file
|
||||
if err := d.Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func Ping(url string) (int, time.Duration, error) {
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
var start, connect, dns, tlsHandshake time.Time
|
||||
trace := &httptrace.ClientTrace{
|
||||
DNSStart: func(dsi httptrace.DNSStartInfo) { dns = time.Now() },
|
||||
DNSDone: func(ddi httptrace.DNSDoneInfo) {
|
||||
fmt.Printf("DNS Done: %v\n", time.Since(dns))
|
||||
},
|
||||
|
||||
TLSHandshakeStart: func() { tlsHandshake = time.Now() },
|
||||
TLSHandshakeDone: func(cs tls.ConnectionState, err error) {
|
||||
fmt.Printf("TLS Handshake: %v\n", time.Since(tlsHandshake))
|
||||
},
|
||||
|
||||
ConnectStart: func(network, addr string) { connect = time.Now() },
|
||||
ConnectDone: func(network, addr string, err error) {
|
||||
fmt.Printf("Connect time: %v\n", time.Since(connect))
|
||||
},
|
||||
|
||||
GotFirstResponseByte: func() {
|
||||
fmt.Printf("Time from start to first byte: %v\n", time.Since(start))
|
||||
},
|
||||
}
|
||||
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
|
||||
start = time.Now()
|
||||
resp, err := http.DefaultTransport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return resp.StatusCode, time.Since(start), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Load config
|
||||
config, err := NewConfig("config.yaml")
|
||||
if err != nil {
|
||||
log.Fatalf("Error loading config: %s", err)
|
||||
}
|
||||
// Print config
|
||||
fmt.Printf("%+v\n", config)
|
||||
|
||||
// create a scheduler
|
||||
s, err := gocron.NewScheduler()
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
|
||||
// Prometheus metrics
|
||||
responseTimeMonitor := prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "labtime_response_time_duration",
|
||||
Help: "The ping time.",
|
||||
}, []string{"target_name"})
|
||||
prometheus.MustRegister(responseTimeMonitor)
|
||||
|
||||
// Intercept the signal to stop the program
|
||||
go func() {
|
||||
sigchan := make(chan os.Signal)
|
||||
signal.Notify(sigchan, os.Interrupt)
|
||||
<-sigchan
|
||||
log.Println("Program killed !")
|
||||
|
||||
// do last actions and wait for all write operations to end
|
||||
|
||||
// when you're done, shut it down
|
||||
err = s.Shutdown()
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
// add a job to the scheduler
|
||||
for _, target := range config.Targets {
|
||||
j, err := s.NewJob(
|
||||
gocron.DurationJob(
|
||||
func(interval int) time.Duration {
|
||||
if interval == 0 {
|
||||
return time.Duration(5) * time.Second
|
||||
}
|
||||
return time.Duration(interval) * time.Second
|
||||
}(target.Interval),
|
||||
),
|
||||
gocron.NewTask(
|
||||
func(url string) {
|
||||
status, elapsedTime, err := Ping(url)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s - Status: %d in %v\n", target.Name, status, elapsedTime.Seconds())
|
||||
// push to Prometheus
|
||||
responseTimeMonitor.With(prometheus.Labels{"target_name": target.Name}).Set(elapsedTime.Seconds())
|
||||
},
|
||||
target.Url,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
// each job has a unique id
|
||||
fmt.Printf("Job %s started with ID: %s\n", target.Name, j.ID().String())
|
||||
}
|
||||
|
||||
// start the scheduler
|
||||
s.Start()
|
||||
|
||||
// // block until you are ready to shut down
|
||||
// select {
|
||||
// // case <-time.After(time.Minute):
|
||||
// }
|
||||
|
||||
// Serve Prometheus metrics
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
http.ListenAndServe(":2112", nil)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
scrape_configs:
|
||||
- job_name: 'labtime'
|
||||
static_configs:
|
||||
- targets: ['host.docker.internal:2112']
|
Loading…
Reference in New Issue