2020-02-23 11:35:47 +00:00
|
|
|
package promscrape
|
|
|
|
|
|
|
|
import (
|
2020-11-01 21:12:13 +00:00
|
|
|
"context"
|
2020-11-21 12:38:54 +00:00
|
|
|
"fmt"
|
2020-02-23 11:35:47 +00:00
|
|
|
"net"
|
2023-10-25 22:29:51 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2020-11-01 21:12:13 +00:00
|
|
|
"sync"
|
2020-02-23 11:35:47 +00:00
|
|
|
"sync/atomic"
|
2020-11-01 21:12:13 +00:00
|
|
|
"time"
|
2020-02-23 11:35:47 +00:00
|
|
|
|
2020-05-05 20:55:55 +00:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil"
|
2020-02-23 11:35:47 +00:00
|
|
|
"github.com/VictoriaMetrics/metrics"
|
|
|
|
)
|
|
|
|
|
2023-09-01 07:34:16 +00:00
|
|
|
func statStdDial(ctx context.Context, _, addr string) (net.Conn, error) {
|
2020-11-01 21:12:13 +00:00
|
|
|
d := getStdDialer()
|
2021-03-16 22:22:57 +00:00
|
|
|
network := netutil.GetTCPNetwork()
|
2020-11-01 21:12:13 +00:00
|
|
|
conn, err := d.DialContext(ctx, network, addr)
|
|
|
|
dialsTotal.Inc()
|
|
|
|
if err != nil {
|
|
|
|
dialErrors.Inc()
|
2023-10-25 22:29:51 +00:00
|
|
|
if !netutil.TCP6Enabled() && !isTCPv4Addr(addr) {
|
2020-12-06 11:15:27 +00:00
|
|
|
err = fmt.Errorf("%w; try -enableTCP6 command-line flag if you scrape ipv6 addresses", err)
|
|
|
|
}
|
2020-11-01 21:12:13 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
conns.Inc()
|
|
|
|
sc := &statConn{
|
|
|
|
Conn: conn,
|
|
|
|
}
|
|
|
|
return sc, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getStdDialer() *net.Dialer {
|
|
|
|
stdDialerOnce.Do(func() {
|
|
|
|
stdDialer = &net.Dialer{
|
|
|
|
Timeout: 30 * time.Second,
|
|
|
|
KeepAlive: 30 * time.Second,
|
|
|
|
DualStack: netutil.TCP6Enabled(),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return stdDialer
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
stdDialer *net.Dialer
|
|
|
|
stdDialerOnce sync.Once
|
|
|
|
)
|
|
|
|
|
2020-02-23 11:35:47 +00:00
|
|
|
var (
|
|
|
|
dialsTotal = metrics.NewCounter(`vm_promscrape_dials_total`)
|
|
|
|
dialErrors = metrics.NewCounter(`vm_promscrape_dial_errors_total`)
|
|
|
|
conns = metrics.NewCounter(`vm_promscrape_conns`)
|
|
|
|
)
|
|
|
|
|
|
|
|
type statConn struct {
|
2024-02-24 00:07:51 +00:00
|
|
|
closed atomic.Int32
|
2020-02-23 11:35:47 +00:00
|
|
|
net.Conn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Read(p []byte) (int, error) {
|
|
|
|
n, err := sc.Conn.Read(p)
|
|
|
|
connReadsTotal.Inc()
|
|
|
|
if err != nil {
|
|
|
|
connReadErrors.Inc()
|
|
|
|
}
|
|
|
|
connBytesRead.Add(n)
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Write(p []byte) (int, error) {
|
|
|
|
n, err := sc.Conn.Write(p)
|
|
|
|
connWritesTotal.Inc()
|
|
|
|
if err != nil {
|
|
|
|
connWriteErrors.Inc()
|
|
|
|
}
|
|
|
|
connBytesWritten.Add(n)
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Close() error {
|
|
|
|
err := sc.Conn.Close()
|
2024-02-24 00:07:51 +00:00
|
|
|
if sc.closed.Add(1) == 1 {
|
2020-02-23 11:35:47 +00:00
|
|
|
conns.Dec()
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
connReadsTotal = metrics.NewCounter(`vm_promscrape_conn_reads_total`)
|
|
|
|
connWritesTotal = metrics.NewCounter(`vm_promscrape_conn_writes_total`)
|
|
|
|
connReadErrors = metrics.NewCounter(`vm_promscrape_conn_read_errors_total`)
|
|
|
|
connWriteErrors = metrics.NewCounter(`vm_promscrape_conn_write_errors_total`)
|
|
|
|
connBytesRead = metrics.NewCounter(`vm_promscrape_conn_bytes_read_total`)
|
|
|
|
connBytesWritten = metrics.NewCounter(`vm_promscrape_conn_bytes_written_total`)
|
|
|
|
)
|
2023-10-25 22:29:51 +00:00
|
|
|
|
|
|
|
func isTCPv4Addr(addr string) bool {
|
|
|
|
s := addr
|
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
n := strings.IndexByte(s, '.')
|
|
|
|
if n < 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !isUint8NumString(s[:n]) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
s = s[n+1:]
|
|
|
|
}
|
|
|
|
n := strings.IndexByte(s, ':')
|
|
|
|
if n < 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !isUint8NumString(s[:n]) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
s = s[n+1:]
|
|
|
|
|
|
|
|
// Verify TCP port
|
|
|
|
n, err := strconv.Atoi(s)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return n >= 0 && n < (1<<16)
|
|
|
|
}
|
|
|
|
|
|
|
|
func isUint8NumString(s string) bool {
|
|
|
|
n, err := strconv.Atoi(s)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return n >= 0 && n < (1<<8)
|
|
|
|
}
|