2019-05-22 23:16:55 +02:00
|
|
|
package netutil
|
|
|
|
|
|
|
|
import (
|
2020-06-30 23:15:34 +02:00
|
|
|
"errors"
|
2019-05-22 23:16:55 +02:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"sync/atomic"
|
|
|
|
|
2023-06-17 07:50:30 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
|
2019-05-22 23:16:55 +02:00
|
|
|
"github.com/VictoriaMetrics/metrics"
|
|
|
|
)
|
|
|
|
|
|
|
|
type connMetrics struct {
|
|
|
|
readCalls *metrics.Counter
|
|
|
|
readBytes *metrics.Counter
|
|
|
|
readErrors *metrics.Counter
|
|
|
|
readTimeouts *metrics.Counter
|
|
|
|
|
|
|
|
writeCalls *metrics.Counter
|
|
|
|
writtenBytes *metrics.Counter
|
|
|
|
writeErrors *metrics.Counter
|
|
|
|
writeTimeouts *metrics.Counter
|
|
|
|
|
|
|
|
closeErrors *metrics.Counter
|
|
|
|
|
2024-07-15 23:00:14 +02:00
|
|
|
conns *metrics.Gauge
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
|
|
|
|
2022-10-25 13:41:56 +02:00
|
|
|
func (cm *connMetrics) init(ms *metrics.Set, group, name, addr string) {
|
|
|
|
cm.readCalls = ms.NewCounter(fmt.Sprintf(`%s_read_calls_total{name=%q, addr=%q}`, group, name, addr))
|
|
|
|
cm.readBytes = ms.NewCounter(fmt.Sprintf(`%s_read_bytes_total{name=%q, addr=%q}`, group, name, addr))
|
|
|
|
cm.readErrors = ms.NewCounter(fmt.Sprintf(`%s_errors_total{name=%q, addr=%q, type="read"}`, group, name, addr))
|
|
|
|
cm.readTimeouts = ms.NewCounter(fmt.Sprintf(`%s_read_timeouts_total{name=%q, addr=%q}`, group, name, addr))
|
2019-05-22 23:16:55 +02:00
|
|
|
|
2022-10-25 13:41:56 +02:00
|
|
|
cm.writeCalls = ms.NewCounter(fmt.Sprintf(`%s_write_calls_total{name=%q, addr=%q}`, group, name, addr))
|
|
|
|
cm.writtenBytes = ms.NewCounter(fmt.Sprintf(`%s_written_bytes_total{name=%q, addr=%q}`, group, name, addr))
|
|
|
|
cm.writeErrors = ms.NewCounter(fmt.Sprintf(`%s_errors_total{name=%q, addr=%q, type="write"}`, group, name, addr))
|
|
|
|
cm.writeTimeouts = ms.NewCounter(fmt.Sprintf(`%s_write_timeouts_total{name=%q, addr=%q}`, group, name, addr))
|
2019-05-22 23:16:55 +02:00
|
|
|
|
2022-10-25 13:41:56 +02:00
|
|
|
cm.closeErrors = ms.NewCounter(fmt.Sprintf(`%s_errors_total{name=%q, addr=%q, type="close"}`, group, name, addr))
|
2019-05-22 23:16:55 +02:00
|
|
|
|
2024-07-15 23:00:14 +02:00
|
|
|
cm.conns = ms.NewGauge(fmt.Sprintf(`%s_conns{name=%q, addr=%q}`, group, name, addr), nil)
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type statConn struct {
|
2024-02-24 01:07:51 +01:00
|
|
|
closeCalls atomic.Uint64
|
2019-10-17 17:22:56 +02:00
|
|
|
|
2019-05-22 23:16:55 +02:00
|
|
|
net.Conn
|
|
|
|
|
|
|
|
cm *connMetrics
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Read(p []byte) (int, error) {
|
2023-06-17 07:50:30 +02:00
|
|
|
startTime := fasttime.UnixTimestamp()
|
2019-05-22 23:16:55 +02:00
|
|
|
n, err := sc.Conn.Read(p)
|
|
|
|
sc.cm.readCalls.Inc()
|
|
|
|
sc.cm.readBytes.Add(n)
|
|
|
|
if err != nil && err != io.EOF {
|
2020-06-30 23:15:34 +02:00
|
|
|
var ne net.Error
|
|
|
|
if errors.As(err, &ne) && ne.Timeout() {
|
2023-09-01 09:34:16 +02:00
|
|
|
// Ignore artificial timeout generated by net/http.Server
|
|
|
|
// See https://cs.opensource.google/go/go/+/refs/tags/go1.20.5:src/net/http/server.go;l=701
|
|
|
|
if fasttime.UnixTimestamp()-startTime > 1 {
|
2023-06-17 07:50:30 +02:00
|
|
|
sc.cm.readTimeouts.Inc()
|
|
|
|
}
|
2019-07-15 22:05:35 +02:00
|
|
|
} else {
|
|
|
|
sc.cm.readErrors.Inc()
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Write(p []byte) (int, error) {
|
|
|
|
n, err := sc.Conn.Write(p)
|
|
|
|
sc.cm.writeCalls.Inc()
|
|
|
|
sc.cm.writtenBytes.Add(n)
|
|
|
|
if err != nil {
|
2020-06-30 23:15:34 +02:00
|
|
|
var ne net.Error
|
|
|
|
if errors.As(err, &ne) && ne.Timeout() {
|
2019-05-22 23:16:55 +02:00
|
|
|
sc.cm.writeTimeouts.Inc()
|
2019-07-15 22:05:35 +02:00
|
|
|
} else {
|
|
|
|
sc.cm.writeErrors.Inc()
|
2019-05-22 23:16:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *statConn) Close() error {
|
2024-02-24 01:07:51 +01:00
|
|
|
n := sc.closeCalls.Add(1)
|
2019-05-22 23:16:55 +02:00
|
|
|
if n > 1 {
|
|
|
|
// The connection has been already closed.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
err := sc.Conn.Close()
|
|
|
|
sc.cm.conns.Dec()
|
|
|
|
if err != nil {
|
|
|
|
sc.cm.closeErrors.Inc()
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|