fix proxy protocol

This commit is contained in:
ginuerzh
2022-09-28 11:47:56 +08:00
parent cf20abf656
commit a1255e52d8
41 changed files with 524 additions and 180 deletions

View File

@ -1,135 +1,52 @@
package metrics
import (
"os"
import "github.com/go-gost/core/metrics"
"github.com/go-gost/core/metrics"
"github.com/prometheus/client_golang/prometheus"
const (
// Number of services. Labels: host.
MetricServicesGauge metrics.MetricName = "gost_services"
// Total service requests. Labels: host, service.
MetricServiceRequestsCounter metrics.MetricName = "gost_service_requests_total"
// Number of in-flight requests. Labels: host, service.
MetricServiceRequestsInFlightGauge metrics.MetricName = "gost_service_requests_in_flight"
// Request duration historgram. Labels: host, service.
MetricServiceRequestsDurationObserver metrics.MetricName = "gost_service_request_duration_seconds"
// Total service input data transfer size in bytes. Labels: host, service.
MetricServiceTransferInputBytesCounter metrics.MetricName = "gost_service_transfer_input_bytes_total"
// Total service output data transfer size in bytes. Labels: host, service.
MetricServiceTransferOutputBytesCounter metrics.MetricName = "gost_service_transfer_output_bytes_total"
// Chain node connect duration histogram. Labels: host, chain, node.
MetricNodeConnectDurationObserver metrics.MetricName = "gost_chain_node_connect_duration_seconds"
// Total service handler errors. Labels: host, service.
MetricServiceHandlerErrorsCounter metrics.MetricName = "gost_service_handler_errors_total"
// Total chain connect errors. Labels: host, chain, node.
MetricChainErrorsCounter metrics.MetricName = "gost_chain_errors_total"
)
type promMetrics struct {
host string
gauges map[metrics.MetricName]*prometheus.GaugeVec
counters map[metrics.MetricName]*prometheus.CounterVec
histograms map[metrics.MetricName]*prometheus.HistogramVec
var (
global metrics.Metrics = Noop()
)
func Init(m metrics.Metrics) {
if m != nil {
global = m
} else {
global = Noop()
}
}
func NewMetrics() metrics.Metrics {
host, _ := os.Hostname()
m := &promMetrics{
host: host,
gauges: map[metrics.MetricName]*prometheus.GaugeVec{
metrics.MetricServicesGauge: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: string(metrics.MetricServicesGauge),
Help: "Current number of services",
},
[]string{"host"}),
metrics.MetricServiceRequestsInFlightGauge: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: string(metrics.MetricServiceRequestsInFlightGauge),
Help: "Current in-flight requests",
},
[]string{"host", "service"}),
},
counters: map[metrics.MetricName]*prometheus.CounterVec{
metrics.MetricServiceRequestsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(metrics.MetricServiceRequestsCounter),
Help: "Total number of requests",
},
[]string{"host", "service"}),
metrics.MetricServiceTransferInputBytesCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(metrics.MetricServiceTransferInputBytesCounter),
Help: "Total service input data transfer size in bytes",
},
[]string{"host", "service"}),
metrics.MetricServiceTransferOutputBytesCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(metrics.MetricServiceTransferOutputBytesCounter),
Help: "Total service output data transfer size in bytes",
},
[]string{"host", "service"}),
metrics.MetricServiceHandlerErrorsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(metrics.MetricServiceHandlerErrorsCounter),
Help: "Total service handler errors",
},
[]string{"host", "service"}),
metrics.MetricChainErrorsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(metrics.MetricChainErrorsCounter),
Help: "Total chain errors",
},
[]string{"host", "chain", "node"}),
},
histograms: map[metrics.MetricName]*prometheus.HistogramVec{
metrics.MetricServiceRequestsDurationObserver: prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: string(metrics.MetricServiceRequestsDurationObserver),
Help: "Distribution of request latencies",
Buckets: []float64{
.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 15, 30, 60,
},
},
[]string{"host", "service"}),
metrics.MetricNodeConnectDurationObserver: prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: string(metrics.MetricNodeConnectDurationObserver),
Help: "Distribution of chain node connect latencies",
Buckets: []float64{
.01, .05, .1, .25, .5, 1, 1.5, 2, 5, 10, 15, 30, 60,
},
},
[]string{"host", "chain", "node"}),
},
}
for k := range m.gauges {
prometheus.MustRegister(m.gauges[k])
}
for k := range m.counters {
prometheus.MustRegister(m.counters[k])
}
for k := range m.histograms {
prometheus.MustRegister(m.histograms[k])
}
return m
func IsEnabled() bool {
return global != Noop()
}
func (m *promMetrics) Gauge(name metrics.MetricName, labels metrics.Labels) metrics.Gauge {
v, ok := m.gauges[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
func GetCounter(name metrics.MetricName, labels metrics.Labels) metrics.Counter {
return global.Counter(name, labels)
}
func (m *promMetrics) Counter(name metrics.MetricName, labels metrics.Labels) metrics.Counter {
v, ok := m.counters[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
func GetGauge(name metrics.MetricName, labels metrics.Labels) metrics.Gauge {
return global.Gauge(name, labels)
}
func (m *promMetrics) Observer(name metrics.MetricName, labels metrics.Labels) metrics.Observer {
v, ok := m.histograms[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
func GetObserver(name metrics.MetricName, labels metrics.Labels) metrics.Observer {
return global.Observer(name, labels)
}

45
metrics/noop.go Normal file
View File

@ -0,0 +1,45 @@
package metrics
import "github.com/go-gost/core/metrics"
var (
nopGauge = &noopGauge{}
nopCounter = &noopCounter{}
nopObserver = &noopObserver{}
noop metrics.Metrics = &noopMetrics{}
)
type noopMetrics struct{}
func Noop() metrics.Metrics {
return noop
}
func (m *noopMetrics) Counter(name metrics.MetricName, labels metrics.Labels) metrics.Counter {
return nopCounter
}
func (m *noopMetrics) Gauge(name metrics.MetricName, labels metrics.Labels) metrics.Gauge {
return nopGauge
}
func (m *noopMetrics) Observer(name metrics.MetricName, labels metrics.Labels) metrics.Observer {
return nopObserver
}
type noopGauge struct{}
func (*noopGauge) Inc() {}
func (*noopGauge) Dec() {}
func (*noopGauge) Add(v float64) {}
func (*noopGauge) Set(v float64) {}
type noopCounter struct{}
func (*noopCounter) Inc() {}
func (*noopCounter) Add(v float64) {}
type noopObserver struct{}
func (*noopObserver) Observe(v float64) {}

135
metrics/prom.go Normal file
View File

@ -0,0 +1,135 @@
package metrics
import (
"os"
"github.com/go-gost/core/metrics"
"github.com/prometheus/client_golang/prometheus"
)
type promMetrics struct {
host string
gauges map[metrics.MetricName]*prometheus.GaugeVec
counters map[metrics.MetricName]*prometheus.CounterVec
histograms map[metrics.MetricName]*prometheus.HistogramVec
}
func NewMetrics() metrics.Metrics {
host, _ := os.Hostname()
m := &promMetrics{
host: host,
gauges: map[metrics.MetricName]*prometheus.GaugeVec{
MetricServicesGauge: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: string(MetricServicesGauge),
Help: "Current number of services",
},
[]string{"host"}),
MetricServiceRequestsInFlightGauge: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: string(MetricServiceRequestsInFlightGauge),
Help: "Current in-flight requests",
},
[]string{"host", "service"}),
},
counters: map[metrics.MetricName]*prometheus.CounterVec{
MetricServiceRequestsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(MetricServiceRequestsCounter),
Help: "Total number of requests",
},
[]string{"host", "service"}),
MetricServiceTransferInputBytesCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(MetricServiceTransferInputBytesCounter),
Help: "Total service input data transfer size in bytes",
},
[]string{"host", "service"}),
MetricServiceTransferOutputBytesCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(MetricServiceTransferOutputBytesCounter),
Help: "Total service output data transfer size in bytes",
},
[]string{"host", "service"}),
MetricServiceHandlerErrorsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(MetricServiceHandlerErrorsCounter),
Help: "Total service handler errors",
},
[]string{"host", "service"}),
MetricChainErrorsCounter: prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: string(MetricChainErrorsCounter),
Help: "Total chain errors",
},
[]string{"host", "chain", "node"}),
},
histograms: map[metrics.MetricName]*prometheus.HistogramVec{
MetricServiceRequestsDurationObserver: prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: string(MetricServiceRequestsDurationObserver),
Help: "Distribution of request latencies",
Buckets: []float64{
.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 15, 30, 60,
},
},
[]string{"host", "service"}),
MetricNodeConnectDurationObserver: prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: string(MetricNodeConnectDurationObserver),
Help: "Distribution of chain node connect latencies",
Buckets: []float64{
.01, .05, .1, .25, .5, 1, 1.5, 2, 5, 10, 15, 30, 60,
},
},
[]string{"host", "chain", "node"}),
},
}
for k := range m.gauges {
prometheus.MustRegister(m.gauges[k])
}
for k := range m.counters {
prometheus.MustRegister(m.counters[k])
}
for k := range m.histograms {
prometheus.MustRegister(m.histograms[k])
}
return m
}
func (m *promMetrics) Gauge(name metrics.MetricName, labels metrics.Labels) metrics.Gauge {
v, ok := m.gauges[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
}
func (m *promMetrics) Counter(name metrics.MetricName, labels metrics.Labels) metrics.Counter {
v, ok := m.counters[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
}
func (m *promMetrics) Observer(name metrics.MetricName, labels metrics.Labels) metrics.Observer {
v, ok := m.histograms[name]
if !ok {
return nil
}
if labels == nil {
labels = metrics.Labels{}
}
labels["host"] = m.host
return v.With(prometheus.Labels(labels))
}

View File

@ -4,6 +4,7 @@ import (
"net"
"net/http"
"github.com/go-gost/core/service"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@ -23,12 +24,12 @@ func PathOption(path string) Option {
}
}
type Service struct {
type metricService struct {
s *http.Server
ln net.Listener
}
func NewService(addr string, opts ...Option) (*Service, error) {
func NewService(addr string, opts ...Option) (service.Service, error) {
ln, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
@ -44,7 +45,7 @@ func NewService(addr string, opts ...Option) (*Service, error) {
mux := http.NewServeMux()
mux.Handle(options.path, promhttp.Handler())
return &Service{
return &metricService{
s: &http.Server{
Handler: mux,
},
@ -52,14 +53,14 @@ func NewService(addr string, opts ...Option) (*Service, error) {
}, nil
}
func (s *Service) Serve() error {
func (s *metricService) Serve() error {
return s.s.Serve(s.ln)
}
func (s *Service) Addr() net.Addr {
func (s *metricService) Addr() net.Addr {
return s.ln.Addr()
}
func (s *Service) Close() error {
func (s *metricService) Close() error {
return s.s.Close()
}

View File

@ -9,6 +9,7 @@ import (
"github.com/go-gost/core/metrics"
xnet "github.com/go-gost/x/internal/net"
"github.com/go-gost/x/internal/net/udp"
xmetrics "github.com/go-gost/x/metrics"
)
var (
@ -22,7 +23,7 @@ type serverConn struct {
}
func WrapConn(service string, c net.Conn) net.Conn {
if !metrics.IsEnabled() {
if !xmetrics.IsEnabled() {
return c
}
return &serverConn{
@ -33,8 +34,8 @@ func WrapConn(service string, c net.Conn) net.Conn {
func (c *serverConn) Read(b []byte) (n int, err error) {
n, err = c.Conn.Read(b)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -45,8 +46,8 @@ func (c *serverConn) Read(b []byte) (n int, err error) {
func (c *serverConn) Write(b []byte) (n int, err error) {
n, err = c.Conn.Write(b)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -70,7 +71,7 @@ type packetConn struct {
}
func WrapPacketConn(service string, pc net.PacketConn) net.PacketConn {
if !metrics.IsEnabled() {
if !xmetrics.IsEnabled() {
return pc
}
return &packetConn{
@ -81,8 +82,8 @@ func WrapPacketConn(service string, pc net.PacketConn) net.PacketConn {
func (c *packetConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
n, addr, err = c.PacketConn.ReadFrom(p)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -93,8 +94,8 @@ func (c *packetConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
func (c *packetConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
n, err = c.PacketConn.WriteTo(p, addr)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -139,8 +140,8 @@ func (c *udpConn) SetWriteBuffer(n int) error {
func (c *udpConn) Read(b []byte) (n int, err error) {
if nc, ok := c.PacketConn.(io.Reader); ok {
n, err = nc.Read(b)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -154,8 +155,8 @@ func (c *udpConn) Read(b []byte) (n int, err error) {
func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
n, addr, err = c.PacketConn.ReadFrom(p)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -167,8 +168,8 @@ func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
func (c *udpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
if nc, ok := c.PacketConn.(udp.ReadUDP); ok {
n, addr, err = nc.ReadFromUDP(b)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -183,8 +184,8 @@ func (c *udpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
func (c *udpConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) {
if nc, ok := c.PacketConn.(udp.ReadUDP); ok {
n, oobn, flags, addr, err = nc.ReadMsgUDP(b, oob)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferInputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferInputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -199,8 +200,8 @@ func (c *udpConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAd
func (c *udpConn) Write(b []byte) (n int, err error) {
if nc, ok := c.PacketConn.(io.Writer); ok {
n, err = nc.Write(b)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -214,8 +215,8 @@ func (c *udpConn) Write(b []byte) (n int, err error) {
func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
n, err = c.PacketConn.WriteTo(p, addr)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -227,8 +228,8 @@ func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
func (c *udpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) {
if nc, ok := c.PacketConn.(udp.WriteUDP); ok {
n, err = nc.WriteToUDP(b, addr)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {
@ -243,8 +244,8 @@ func (c *udpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) {
func (c *udpConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) {
if nc, ok := c.PacketConn.(udp.WriteUDP); ok {
n, oobn, err = nc.WriteMsgUDP(b, oob, addr)
if counter := metrics.GetCounter(
metrics.MetricServiceTransferOutputBytesCounter,
if counter := xmetrics.GetCounter(
xmetrics.MetricServiceTransferOutputBytesCounter,
metrics.Labels{
"service": c.service,
}); counter != nil {

View File

@ -3,7 +3,7 @@ package wrapper
import (
"net"
"github.com/go-gost/core/metrics"
xmetrics "github.com/go-gost/x/metrics"
)
type listener struct {
@ -12,7 +12,7 @@ type listener struct {
}
func WrapListener(service string, ln net.Listener) net.Listener {
if !metrics.IsEnabled() {
if !xmetrics.IsEnabled() {
return ln
}