mirror of
https://github.com/henrygd/beszel.git
synced 2026-09-21 00:47:47 +02:00
Co-authored-by: Sven van Ginkel <svenvanginkel@icloud.com> Co-authored-by: xiaomiku01 <xiaomiku01@outlook.com>
This commit is contained in:
105
agent/network_monitor_probe.go
Normal file
105
agent/network_monitor_probe.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/henrygd/beszel/internal/entities/monitor"
|
||||
)
|
||||
|
||||
// monitorProbe performs one check. Errors are recorded as loss by the task runner.
|
||||
// Implementations must honor cancellation and bound their execution time.
|
||||
type monitorProbe func(context.Context, monitor.Config) (int64, error)
|
||||
|
||||
func networkMonitorProbe(client *http.Client) monitorProbe {
|
||||
return func(ctx context.Context, config monitor.Config) (int64, error) {
|
||||
switch config.Protocol {
|
||||
case "icmp":
|
||||
return monitorICMP(ctx, config.Target)
|
||||
case "tcp":
|
||||
return monitorTCP(ctx, config.Target, config.Port)
|
||||
case "http":
|
||||
return monitorHTTP(ctx, client, config.Target)
|
||||
case "dns":
|
||||
return monitorDNS(ctx, config.Target)
|
||||
default:
|
||||
return -1, fmt.Errorf("unknown monitor protocol: %s", config.Protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// monitorTCP measures connection establishment time, including address fallback
|
||||
// but excluding DNS resolution.
|
||||
// Returns -1 and an error on failure.
|
||||
func monitorTCP(ctx context.Context, target string, port uint16) (int64, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Resolve DNS first, outside the timing window but within the probe deadline.
|
||||
ips, err := net.DefaultResolver.LookupHost(ctx, target)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return -1, errors.New("no addresses resolved for TCP monitor")
|
||||
}
|
||||
portString := fmt.Sprintf("%d", port)
|
||||
deadline, _ := ctx.Deadline()
|
||||
|
||||
// Share the remaining probe budget across addresses so an unresponsive
|
||||
// first address cannot consume all the time available for alternatives.
|
||||
start := time.Now()
|
||||
for i, ip := range ips {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
dialer := net.Dialer{Timeout: time.Until(deadline) / time.Duration(len(ips)-i)}
|
||||
var conn net.Conn
|
||||
conn, err = dialer.DialContext(ctx, "tcp", net.JoinHostPort(ip, portString))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
responseUs := time.Since(start).Microseconds()
|
||||
conn.Close()
|
||||
return responseUs, nil
|
||||
}
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// monitorDNS measures DNS resolution response time in microseconds. Returns -1 and an error on failure.
|
||||
func monitorDNS(ctx context.Context, target string) (int64, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
start := time.Now()
|
||||
ips, err := net.DefaultResolver.LookupHost(ctx, target)
|
||||
if err != nil || len(ips) == 0 {
|
||||
return -1, err
|
||||
}
|
||||
return time.Since(start).Microseconds(), nil
|
||||
}
|
||||
|
||||
// monitorHTTP measures HTTP GET request response in microseconds. Returns -1 and an error on failure.
|
||||
func monitorHTTP(ctx context.Context, client *http.Client, url string) (int64, error) {
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
start := time.Now()
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
return -1, fmt.Errorf("HTTP error: %s", resp.Status)
|
||||
}
|
||||
return time.Since(start).Microseconds(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user