added code to export metrics
This commit is contained in:
parent
810356efe5
commit
c5f63328b2
8
Makefile
8
Makefile
@ -11,13 +11,16 @@ VERSION=1.0.0
|
|||||||
SRCS=\
|
SRCS=\
|
||||||
client.go \
|
client.go \
|
||||||
client-ctl.go \
|
client-ctl.go \
|
||||||
|
client-metrics.go \
|
||||||
client-peer.go \
|
client-peer.go \
|
||||||
hodu.go \
|
hodu.go \
|
||||||
hodu.pb.go \
|
hodu.pb.go \
|
||||||
hodu_grpc.pb.go \
|
hodu_grpc.pb.go \
|
||||||
|
jwt.go \
|
||||||
packet.go \
|
packet.go \
|
||||||
server.go \
|
server.go \
|
||||||
server-ctl.go \
|
server-ctl.go \
|
||||||
|
server-metrics.go \
|
||||||
server-peer.go \
|
server-peer.go \
|
||||||
server-proxy.go \
|
server-proxy.go \
|
||||||
system.go \
|
system.go \
|
||||||
@ -49,6 +52,9 @@ clean:
|
|||||||
go clean -x -i
|
go clean -x -i
|
||||||
rm -f $(NAME)
|
rm -f $(NAME)
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -x
|
||||||
|
|
||||||
hodu.pb.go: hodu.proto
|
hodu.pb.go: hodu.proto
|
||||||
protoc --go_out=. --go_opt=paths=source_relative \
|
protoc --go_out=. --go_opt=paths=source_relative \
|
||||||
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
||||||
@ -75,4 +81,4 @@ cmd/tls.crt:
|
|||||||
cmd/tls.key:
|
cmd/tls.key:
|
||||||
openssl req -x509 -newkey rsa:4096 -keyout cmd/tls.key -out cmd/tls.crt -sha256 -days 36500 -nodes -subj "/CN=$(NAME)" --addext "subjectAltName=DNS:$(NAME),IP:10.0.0.1,IP:::1"
|
openssl req -x509 -newkey rsa:4096 -keyout cmd/tls.key -out cmd/tls.crt -sha256 -days 36500 -nodes -subj "/CN=$(NAME)" --addext "subjectAltName=DNS:$(NAME),IP:10.0.0.1,IP:::1"
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean test
|
||||||
|
@ -3,8 +3,6 @@ package hodu
|
|||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
//import "net/url"
|
|
||||||
import "runtime"
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "strings"
|
import "strings"
|
||||||
import "time"
|
import "time"
|
||||||
@ -85,14 +83,7 @@ type json_out_client_peer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type json_out_client_stats struct {
|
type json_out_client_stats struct {
|
||||||
CPUs int `json:"cpus"`
|
json_out_go_stats
|
||||||
Goroutines int `json:"goroutines"`
|
|
||||||
|
|
||||||
NumGCs uint32 `json:"num-gcs"`
|
|
||||||
HeapAllocBytes uint64 `json:"memory-alloc-bytes"`
|
|
||||||
MemAllocs uint64 `json:"memory-num-allocs"`
|
|
||||||
MemFrees uint64 `json:"memory-num-frees"`
|
|
||||||
|
|
||||||
ClientConns int64 `json:"client-conns"`
|
ClientConns int64 `json:"client-conns"`
|
||||||
ClientRoutes int64 `json:"client-routes"`
|
ClientRoutes int64 `json:"client-routes"`
|
||||||
ClientPeers int64 `json:"client-peers"`
|
ClientPeers int64 `json:"client-peers"`
|
||||||
@ -140,7 +131,7 @@ type client_ctl_stats struct {
|
|||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
|
|
||||||
func (ctl *client_ctl) GetId() string {
|
func (ctl *client_ctl) Id() string {
|
||||||
return ctl.id
|
return ctl.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,14 +822,7 @@ func (ctl *client_ctl_stats) ServeHTTP(w http.ResponseWriter, req *http.Request)
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
var stats json_out_client_stats
|
var stats json_out_client_stats
|
||||||
var mstat runtime.MemStats
|
stats.from_runtime_stats()
|
||||||
runtime.ReadMemStats(&mstat)
|
|
||||||
stats.CPUs = runtime.NumCPU()
|
|
||||||
stats.Goroutines = runtime.NumGoroutine()
|
|
||||||
stats.NumGCs = mstat.NumGC
|
|
||||||
stats.HeapAllocBytes = mstat.HeapAlloc
|
|
||||||
stats.MemAllocs = mstat.Mallocs
|
|
||||||
stats.MemFrees = mstat.Frees
|
|
||||||
stats.ClientConns = c.stats.conns.Load()
|
stats.ClientConns = c.stats.conns.Load()
|
||||||
stats.ClientRoutes = c.stats.routes.Load()
|
stats.ClientRoutes = c.stats.routes.Load()
|
||||||
stats.ClientPeers = c.stats.peers.Load()
|
stats.ClientPeers = c.stats.peers.Load()
|
||||||
|
85
client-metrics.go
Normal file
85
client-metrics.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package hodu
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
type ClientCollector struct {
|
||||||
|
client *Client
|
||||||
|
BuildInfo *prometheus.Desc
|
||||||
|
ClientConns *prometheus.Desc
|
||||||
|
ClientRoutes *prometheus.Desc
|
||||||
|
ClientPeers *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientCollector returns a new ClientCollector with all prometheus.Desc initialized
|
||||||
|
func NewClientCollector(client *Client) ClientCollector {
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
prefix = client.Name() + "_"
|
||||||
|
return ClientCollector{
|
||||||
|
client: client,
|
||||||
|
|
||||||
|
BuildInfo: prometheus.NewDesc(
|
||||||
|
prefix + "build_info",
|
||||||
|
"Build information",
|
||||||
|
[]string{
|
||||||
|
"goarch",
|
||||||
|
"goos",
|
||||||
|
"goversion",
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
ClientConns: prometheus.NewDesc(
|
||||||
|
prefix + "client_conns",
|
||||||
|
"Number of client connections from clients",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
ClientRoutes: prometheus.NewDesc(
|
||||||
|
prefix + "client_routes",
|
||||||
|
"Number of client-side routes",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
ClientPeers: prometheus.NewDesc(
|
||||||
|
prefix + "client_peers",
|
||||||
|
"Number of client-side peers",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClientCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- c.BuildInfo
|
||||||
|
ch <- c.ClientConns
|
||||||
|
ch <- c.ClientRoutes
|
||||||
|
ch <- c.ClientPeers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClientCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.BuildInfo,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1,
|
||||||
|
runtime.GOARCH,
|
||||||
|
runtime.GOOS,
|
||||||
|
runtime.Version(),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ClientConns,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.client.stats.conns.Load()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ClientRoutes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.client.stats.routes.Load()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ClientPeers,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.client.stats.peers.Load()),
|
||||||
|
)
|
||||||
|
}
|
32
client.go
32
client.go
@ -18,6 +18,8 @@ import "google.golang.org/grpc/credentials"
|
|||||||
import "google.golang.org/grpc/credentials/insecure"
|
import "google.golang.org/grpc/credentials/insecure"
|
||||||
import "google.golang.org/grpc/peer"
|
import "google.golang.org/grpc/peer"
|
||||||
import "google.golang.org/grpc/status"
|
import "google.golang.org/grpc/status"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
||||||
type PacketStreamClient grpc.BidiStreamingClient[Packet, Packet]
|
type PacketStreamClient grpc.BidiStreamingClient[Packet, Packet]
|
||||||
|
|
||||||
@ -51,6 +53,8 @@ type ClientConfigActive struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
Named
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctx_cancel context.CancelFunc
|
ctx_cancel context.CancelFunc
|
||||||
ctltlscfg *tls.Config
|
ctltlscfg *tls.Config
|
||||||
@ -78,6 +82,7 @@ type Client struct {
|
|||||||
log Logger
|
log Logger
|
||||||
route_persister ClientRoutePersister
|
route_persister ClientRoutePersister
|
||||||
|
|
||||||
|
promreg *prometheus.Registry
|
||||||
stats struct {
|
stats struct {
|
||||||
conns atomic.Int64
|
conns atomic.Int64
|
||||||
routes atomic.Int64
|
routes atomic.Int64
|
||||||
@ -859,7 +864,7 @@ func (cts *ClientConn) add_client_routes(routes []ClientRouteConfig) error {
|
|||||||
for _, v = range routes {
|
for _, v = range routes {
|
||||||
_, err = cts.AddNewClientRoute(&v)
|
_, err = cts.AddNewClientRoute(&v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add client route for %s - %s", v, err.Error())
|
return fmt.Errorf("unable to add client route for %v - %s", v, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,7 +1224,7 @@ func (hlw *client_ctl_log_writer) Write(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ClientHttpHandler interface {
|
type ClientHttpHandler interface {
|
||||||
GetId() string
|
Id() string
|
||||||
ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error)
|
ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,19 +1258,20 @@ func (c *Client) wrap_http_handler(handler ClientHttpHandler) http.Handler {
|
|||||||
|
|
||||||
if status_code > 0 {
|
if status_code > 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.log.Write(handler.GetId(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
|
c.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
|
||||||
} else {
|
} else {
|
||||||
c.log.Write(handler.GetId(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
|
c.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(ctx context.Context, logger Logger, ctl_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, rpc_max int, peer_max int, peer_conn_tmout time.Duration) *Client {
|
func NewClient(ctx context.Context, name string, logger Logger, ctl_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, rpc_max int, peer_max int, peer_conn_tmout time.Duration) *Client {
|
||||||
var c Client
|
var c Client
|
||||||
var i int
|
var i int
|
||||||
var hs_log *log.Logger
|
var hs_log *log.Logger
|
||||||
|
|
||||||
|
c.name = name
|
||||||
c.ctx, c.ctx_cancel = context.WithCancel(ctx)
|
c.ctx, c.ctx_cancel = context.WithCancel(ctx)
|
||||||
c.ctltlscfg = ctltlscfg
|
c.ctltlscfg = ctltlscfg
|
||||||
c.rpctlscfg = rpctlscfg
|
c.rpctlscfg = rpctlscfg
|
||||||
@ -1298,6 +1304,14 @@ func NewClient(ctx context.Context, logger Logger, ctl_addrs []string, ctl_prefi
|
|||||||
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/stats",
|
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/stats",
|
||||||
c.wrap_http_handler(&client_ctl_stats{client_ctl{c: &c, id: HS_ID_CTL}}))
|
c.wrap_http_handler(&client_ctl_stats{client_ctl{c: &c, id: HS_ID_CTL}}))
|
||||||
|
|
||||||
|
// TODO: make this optional. add this endpoint only if it's enabled...
|
||||||
|
c.promreg = prometheus.NewRegistry()
|
||||||
|
c.promreg.MustRegister(prometheus.NewGoCollector())
|
||||||
|
c.promreg.MustRegister(NewClientCollector(&c))
|
||||||
|
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/metrics",
|
||||||
|
promhttp.HandlerFor(c.promreg, promhttp.HandlerOpts{ EnableOpenMetrics: true }))
|
||||||
|
|
||||||
|
|
||||||
c.ctl_addr = make([]string, len(ctl_addrs))
|
c.ctl_addr = make([]string, len(ctl_addrs))
|
||||||
c.ctl = make([]*http.Server, len(ctl_addrs))
|
c.ctl = make([]*http.Server, len(ctl_addrs))
|
||||||
copy(c.ctl_addr, ctl_addrs)
|
copy(c.ctl_addr, ctl_addrs)
|
||||||
@ -1666,3 +1680,11 @@ func (c *Client) WriteLog(id string, level LogLevel, fmtstr string, args ...inte
|
|||||||
func (c *Client) SetRoutePersister(persister ClientRoutePersister) {
|
func (c *Client) SetRoutePersister(persister ClientRoutePersister) {
|
||||||
c.route_persister = persister
|
c.route_persister = persister
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) AddCtlMetricsCollector(col prometheus.Collector) error {
|
||||||
|
return c.promreg.Register(col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveCtlMetricsCollector(col prometheus.Collector) bool {
|
||||||
|
return c.promreg.Unregister(col)
|
||||||
|
}
|
||||||
|
@ -42,6 +42,12 @@ type ClientTLSConfig struct {
|
|||||||
ServerName string `yaml:"server-name"`
|
ServerName string `yaml:"server-name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasicAuthConfig struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Users []string `yaml:"users"`
|
||||||
|
UserFile string `yaml:"user-file"`
|
||||||
|
}
|
||||||
|
|
||||||
type CTLServiceConfig struct {
|
type CTLServiceConfig struct {
|
||||||
Prefix string `yaml:"prefix"` // url prefix for control channel endpoints
|
Prefix string `yaml:"prefix"` // url prefix for control channel endpoints
|
||||||
Addrs []string `yaml:"addresses"`
|
Addrs []string `yaml:"addresses"`
|
||||||
|
@ -158,6 +158,7 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx
|
|||||||
|
|
||||||
s, err = hodu.NewServer(
|
s, err = hodu.NewServer(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
|
HODU_NAME,
|
||||||
logger,
|
logger,
|
||||||
ctl_addrs,
|
ctl_addrs,
|
||||||
rpc_addrs,
|
rpc_addrs,
|
||||||
@ -315,6 +316,7 @@ func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string,
|
|||||||
}
|
}
|
||||||
c = hodu.NewClient(
|
c = hodu.NewClient(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
|
HODU_NAME,
|
||||||
logger,
|
logger,
|
||||||
ctl_addrs,
|
ctl_addrs,
|
||||||
ctl_prefix,
|
ctl_prefix,
|
||||||
|
12
go.mod
12
go.mod
@ -12,4 +12,14 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||||
|
)
|
||||||
|
16
go.sum
16
go.sum
@ -1,5 +1,21 @@
|
|||||||
|
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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
|
76
hodu.go
76
hodu.go
@ -10,7 +10,6 @@ import "strings"
|
|||||||
import "sync"
|
import "sync"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
|
||||||
const HODU_RPC_VERSION uint32 = 0x010000
|
const HODU_RPC_VERSION uint32 = 0x010000
|
||||||
|
|
||||||
type LogLevel int
|
type LogLevel int
|
||||||
@ -29,6 +28,10 @@ const LOG_NONE LogMask = LogMask(0)
|
|||||||
var IPV4_PREFIX_ZERO = netip.MustParsePrefix("0.0.0.0/0")
|
var IPV4_PREFIX_ZERO = netip.MustParsePrefix("0.0.0.0/0")
|
||||||
var IPV6_PREFIX_ZERO = netip.MustParsePrefix("::/0")
|
var IPV6_PREFIX_ZERO = netip.MustParsePrefix("::/0")
|
||||||
|
|
||||||
|
type Named struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
Write(id string, level LogLevel, fmtstr string, args ...interface{})
|
Write(id string, level LogLevel, fmtstr string, args ...interface{})
|
||||||
WriteWithCallDepth(id string, level LogLevel, call_depth int, fmtstr string, args ...interface{})
|
WriteWithCallDepth(id string, level LogLevel, call_depth int, fmtstr string, args ...interface{})
|
||||||
@ -45,6 +48,43 @@ type Service interface {
|
|||||||
WriteLog(id string, level LogLevel, fmtstr string, args ...interface{})
|
WriteLog(id string, level LogLevel, fmtstr string, args ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type json_out_go_stats struct {
|
||||||
|
CPUs int `json:"cpus"`
|
||||||
|
Goroutines int `json:"goroutines"`
|
||||||
|
NumCgoCalls int64 `json:"num-cgo-calls"`
|
||||||
|
NumGCs uint32 `json:"num-gcs"`
|
||||||
|
AllocBytes uint64 `json:"memory-alloc-bytes"`
|
||||||
|
TotalAllocBytes uint64 `json:"memory-total-alloc-bytes"`
|
||||||
|
SysBytes uint64 `json:"memory-sys-bytes"`
|
||||||
|
Lookups uint64 `json:"memory-lookups"`
|
||||||
|
MemAllocs uint64 `json:"memory-num-allocs"`
|
||||||
|
MemFrees uint64 `json:"memory-num-frees"`
|
||||||
|
|
||||||
|
HeapAllocBytes uint64 `json:"memory-heap-alloc-bytes"`
|
||||||
|
HeapSysBytes uint64 `json:"memory-heap-sys-bytes"`
|
||||||
|
HeapIdleBytes uint64 `json:"memory-heap-idle-bytes"`
|
||||||
|
HeapInuseBytes uint64 `json:"memory-heap-inuse-bytes"`
|
||||||
|
HeapReleasedBytes uint64 `json:"memory-heap-released-bytes"`
|
||||||
|
HeapObjects uint64 `json:"memory-heap-objects"`
|
||||||
|
StackInuseBytes uint64 `json:"memory-stack-inuse-bytes"`
|
||||||
|
StackSysBytes uint64 `json:"memory-stack-sys-bytes"`
|
||||||
|
MSpanInuseBytes uint64 `json:"memory-mspan-inuse-bytes"`
|
||||||
|
MSpanSysBytes uint64 `json:"memory-mspan-sys-bytes"`
|
||||||
|
MCacheInuseBytes uint64 `json:"memory-mcache-inuse-bytes"`
|
||||||
|
MCacheSysBytes uint64 `json:"memory-mcache-sys-bytes"`
|
||||||
|
BuckHashSysBytes uint64 `json:"memory-buck-hash-sys-bytes"`
|
||||||
|
GCSysBytes uint64 `json:"memory-gc-sys-bytes"`
|
||||||
|
OtherSysBytes uint64 `json:"memory-other-sys-bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Named) SetName(name string) {
|
||||||
|
n.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Named) Name() string {
|
||||||
|
return n.name
|
||||||
|
}
|
||||||
|
|
||||||
func TcpAddrStrClass(addr string) string {
|
func TcpAddrStrClass(addr string) string {
|
||||||
// the string is supposed to be addr:port
|
// the string is supposed to be addr:port
|
||||||
|
|
||||||
@ -221,3 +261,37 @@ func proxy_info_to_server_route(pi *ServerRouteProxyInfo) *ServerRoute {
|
|||||||
SvcPermNet: pi.SvcPermNet,
|
SvcPermNet: pi.SvcPermNet,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (stats *json_out_go_stats) from_runtime_stats() {
|
||||||
|
var mstat runtime.MemStats
|
||||||
|
|
||||||
|
runtime.ReadMemStats(&mstat)
|
||||||
|
|
||||||
|
stats.CPUs = runtime.NumCPU()
|
||||||
|
stats.Goroutines = runtime.NumGoroutine()
|
||||||
|
stats.NumCgoCalls = runtime.NumCgoCall()
|
||||||
|
stats.NumGCs = mstat.NumGC
|
||||||
|
|
||||||
|
stats.AllocBytes = mstat.Alloc
|
||||||
|
stats.TotalAllocBytes = mstat.TotalAlloc
|
||||||
|
stats.SysBytes = mstat.Sys
|
||||||
|
stats.Lookups = mstat.Lookups
|
||||||
|
stats.MemAllocs = mstat.Mallocs
|
||||||
|
stats.MemFrees = mstat.Frees
|
||||||
|
|
||||||
|
stats.HeapAllocBytes = mstat.HeapAlloc
|
||||||
|
stats.HeapSysBytes = mstat.HeapSys
|
||||||
|
stats.HeapIdleBytes = mstat.HeapIdle
|
||||||
|
stats.HeapInuseBytes = mstat.HeapInuse
|
||||||
|
stats.HeapReleasedBytes = mstat.HeapReleased
|
||||||
|
stats.HeapObjects = mstat.HeapObjects
|
||||||
|
stats.StackInuseBytes = mstat.StackInuse
|
||||||
|
stats.StackSysBytes = mstat.StackSys
|
||||||
|
stats.MSpanInuseBytes = mstat.MSpanInuse
|
||||||
|
stats.MSpanSysBytes = mstat.MSpanSys
|
||||||
|
stats.MCacheInuseBytes = mstat.MCacheInuse
|
||||||
|
stats.MCacheSysBytes = mstat.MCacheSys
|
||||||
|
stats.BuckHashSysBytes = mstat.BuckHashSys
|
||||||
|
stats.GCSysBytes = mstat.GCSys
|
||||||
|
stats.OtherSysBytes = mstat.OtherSys
|
||||||
|
}
|
||||||
|
123
jwt.go
Normal file
123
jwt.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package hodu
|
||||||
|
|
||||||
|
import "crypto"
|
||||||
|
import "crypto/hmac"
|
||||||
|
import "crypto/rand"
|
||||||
|
import "crypto/rsa"
|
||||||
|
import "encoding/base64"
|
||||||
|
import "encoding/json"
|
||||||
|
import "fmt"
|
||||||
|
import "hash"
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func Sign(data []byte, privkey *rsa.PrivateKey) ([]byte, error) {
|
||||||
|
var h hash.Hash
|
||||||
|
|
||||||
|
h = crypto.SHA512.New()
|
||||||
|
h.Write(data)
|
||||||
|
|
||||||
|
fmt.Printf("%+v\n", h.Sum(nil))
|
||||||
|
return rsa.SignPKCS1v15(rand.Reader, privkey, crypto.SHA512, h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Verify(data []byte, pubkey *rsa.PublicKey, sig []byte) error {
|
||||||
|
var h hash.Hash
|
||||||
|
|
||||||
|
h = crypto.SHA512.New()
|
||||||
|
h.Write(data)
|
||||||
|
|
||||||
|
return rsa.VerifyPKCS1v15(pubkey, crypto.SHA512, h.Sum(nil), sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignHS512(data []byte, key string) ([]byte, error) {
|
||||||
|
var h hash.Hash
|
||||||
|
|
||||||
|
h = hmac.New(crypto.SHA512.New, []byte(key))
|
||||||
|
h.Write(data)
|
||||||
|
|
||||||
|
return h.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyHS512(data []byte, key string, sig []byte) error {
|
||||||
|
var h hash.Hash
|
||||||
|
|
||||||
|
h = crypto.SHA512.New()
|
||||||
|
h.Write(data)
|
||||||
|
|
||||||
|
if !hmac.Equal(h.Sum(nil), sig) { return fmt.Errorf("invalid signature") }
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWT struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWTHeader struct {
|
||||||
|
Algo string `json:"alg"`
|
||||||
|
Type string `json:"typ"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWTClaimMap map[string]interface{}
|
||||||
|
|
||||||
|
func (j *JWT) Sign(claims interface{}) (string, error) {
|
||||||
|
var h JWTHeader
|
||||||
|
var hb []byte
|
||||||
|
var cb []byte
|
||||||
|
var ss string
|
||||||
|
var sb []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
h.Algo = "HS512"
|
||||||
|
h.Type = "JWT"
|
||||||
|
|
||||||
|
hb, err = json.Marshal(h)
|
||||||
|
if err != nil { return "", err }
|
||||||
|
|
||||||
|
cb, err = json.Marshal(claims)
|
||||||
|
if err != nil { return "", err }
|
||||||
|
|
||||||
|
ss = base64.RawURLEncoding.EncodeToString(hb) + "." + base64.RawURLEncoding.EncodeToString(cb)
|
||||||
|
sb, err = SignHS512([]byte(ss), "hello")
|
||||||
|
if err != nil { return "", err }
|
||||||
|
|
||||||
|
fmt.Printf ("%+v %+v %s\n", string(hb), string(cb), (ss + "." + base64.RawURLEncoding.EncodeToString(sb)))
|
||||||
|
return ss + "." + base64.RawURLEncoding.EncodeToString(sb), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JWT) Verify(tok string) error {
|
||||||
|
var segs []string
|
||||||
|
var hb []byte
|
||||||
|
var cb []byte
|
||||||
|
var sb []byte
|
||||||
|
var jh JWTHeader
|
||||||
|
var jcm JWTClaimMap
|
||||||
|
var x string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
segs = strings.Split(tok, ".")
|
||||||
|
if len(segs) != 3 { return fmt.Errorf("invalid token") }
|
||||||
|
|
||||||
|
hb, err = base64.RawURLEncoding.DecodeString(segs[0])
|
||||||
|
if err != nil { return fmt.Errorf("invalid header - %s", err.Error()) }
|
||||||
|
err = json.Unmarshal(hb, &jh)
|
||||||
|
if err != nil { return fmt.Errorf("invalid header - %s", err.Error()) }
|
||||||
|
fmt.Printf ("DECODED HEADER [%+v]\n", jh)
|
||||||
|
|
||||||
|
cb, err = base64.RawURLEncoding.DecodeString(segs[1])
|
||||||
|
if err != nil { return fmt.Errorf("invalid claims - %s", err.Error()) }
|
||||||
|
err = json.Unmarshal(cb, &jcm)
|
||||||
|
if err != nil { return fmt.Errorf("invalid header - %s", err.Error()) }
|
||||||
|
fmt.Printf ("DECODED CLAIMS [%+v]\n", jcm)
|
||||||
|
|
||||||
|
x, err = j.Sign(jcm)
|
||||||
|
if err != nil { return err }
|
||||||
|
fmt.Printf ("VERIFICATION OK...\n")
|
||||||
|
|
||||||
|
if x != tok { return fmt.Errorf("signature mismatch") }
|
||||||
|
|
||||||
|
// sb, err = base64.RawURLEncoding.DecodeString(segs[2])
|
||||||
|
// if err != nil { return fmt.Errorf("invalid signature - %s", err.Error()) }
|
||||||
|
|
||||||
|
_ = sb
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
26
jwt_test.go
Normal file
26
jwt_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package hodu_test
|
||||||
|
|
||||||
|
import "hodu"
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestJwt(t *testing.T) {
|
||||||
|
var j hodu.JWT
|
||||||
|
var tok string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
type JWTClaim struct {
|
||||||
|
Abc string `json:"abc"`
|
||||||
|
Donkey string `json:"donkey"`
|
||||||
|
IssuedAt int `json:"iat"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var jc JWTClaim
|
||||||
|
jc.Abc = "def"
|
||||||
|
jc.Donkey = "kong"
|
||||||
|
jc.IssuedAt = 111
|
||||||
|
tok, err = j.Sign(&jc)
|
||||||
|
if err != nil { t.Fatalf("signing failure - %s", err.Error()) }
|
||||||
|
|
||||||
|
err = j.Verify(tok)
|
||||||
|
if err != nil { t.Fatalf("verification failure - %s", err.Error()) }
|
||||||
|
}
|
@ -2,7 +2,6 @@ package hodu
|
|||||||
|
|
||||||
import "encoding/json"
|
import "encoding/json"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
import "runtime"
|
|
||||||
|
|
||||||
type json_out_server_conn struct {
|
type json_out_server_conn struct {
|
||||||
Id ConnId `json:"id"`
|
Id ConnId `json:"id"`
|
||||||
@ -21,19 +20,13 @@ type json_out_server_route struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type json_out_server_stats struct {
|
type json_out_server_stats struct {
|
||||||
CPUs int `json:"cpus"`
|
json_out_go_stats
|
||||||
Goroutines int `json:"goroutines"`
|
|
||||||
|
|
||||||
NumGCs uint32 `json:"num-gcs"`
|
|
||||||
HeapAllocBytes uint64 `json:"memory-alloc-bytes"`
|
|
||||||
MemAllocs uint64 `json:"memory-num-allocs"`
|
|
||||||
MemFrees uint64 `json:"memory-num-frees"`
|
|
||||||
|
|
||||||
ServerConns int64 `json:"server-conns"`
|
ServerConns int64 `json:"server-conns"`
|
||||||
ServerRoutes int64 `json:"server-routes"`
|
ServerRoutes int64 `json:"server-routes"`
|
||||||
ServerPeers int64 `json:"server-peers"`
|
ServerPeers int64 `json:"server-peers"`
|
||||||
|
|
||||||
SshProxySessions int64 `json:"ssh-proxy-session"`
|
SshProxySessions int64 `json:"ssh-pxy-sessions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
@ -65,7 +58,7 @@ type server_ctl_stats struct {
|
|||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
|
|
||||||
func (ctl *server_ctl) GetId() string {
|
func (ctl *server_ctl) Id() string {
|
||||||
return ctl.id
|
return ctl.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,15 +349,7 @@ func (ctl *server_ctl_stats) ServeHTTP(w http.ResponseWriter, req *http.Request)
|
|||||||
switch req.Method {
|
switch req.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
var stats json_out_server_stats
|
var stats json_out_server_stats
|
||||||
var mstat runtime.MemStats
|
stats.from_runtime_stats()
|
||||||
|
|
||||||
runtime.ReadMemStats(&mstat)
|
|
||||||
stats.CPUs = runtime.NumCPU()
|
|
||||||
stats.Goroutines = runtime.NumGoroutine()
|
|
||||||
stats.NumGCs = mstat.NumGC
|
|
||||||
stats.HeapAllocBytes = mstat.HeapAlloc
|
|
||||||
stats.MemAllocs = mstat.Mallocs
|
|
||||||
stats.MemFrees = mstat.Frees
|
|
||||||
stats.ServerConns = s.stats.conns.Load()
|
stats.ServerConns = s.stats.conns.Load()
|
||||||
stats.ServerRoutes = s.stats.routes.Load()
|
stats.ServerRoutes = s.stats.routes.Load()
|
||||||
stats.ServerPeers = s.stats.peers.Load()
|
stats.ServerPeers = s.stats.peers.Load()
|
||||||
|
98
server-metrics.go
Normal file
98
server-metrics.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package hodu
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
type ServerCollector struct {
|
||||||
|
server *Server
|
||||||
|
BuildInfo *prometheus.Desc
|
||||||
|
ServerConns *prometheus.Desc
|
||||||
|
ServerRoutes *prometheus.Desc
|
||||||
|
ServerPeers *prometheus.Desc
|
||||||
|
SshProxySessions *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerCollector returns a new ServerCollector with all prometheus.Desc initialized
|
||||||
|
func NewServerCollector(server *Server) ServerCollector {
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
prefix = server.Name() + "_"
|
||||||
|
return ServerCollector{
|
||||||
|
server: server,
|
||||||
|
|
||||||
|
BuildInfo: prometheus.NewDesc(
|
||||||
|
prefix + "build_info",
|
||||||
|
"Build information",
|
||||||
|
[]string{
|
||||||
|
"goarch",
|
||||||
|
"goos",
|
||||||
|
"goversion",
|
||||||
|
}, nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
ServerConns: prometheus.NewDesc(
|
||||||
|
prefix + "server_conns",
|
||||||
|
"Number of server connections from clients",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
ServerRoutes: prometheus.NewDesc(
|
||||||
|
prefix + "server_routes",
|
||||||
|
"Number of server-side routes",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
ServerPeers: prometheus.NewDesc(
|
||||||
|
prefix + "server_peers",
|
||||||
|
"Number of server-side peers",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
SshProxySessions: prometheus.NewDesc(
|
||||||
|
prefix + "ssh_pxy_sessions",
|
||||||
|
"Number of SSH proxy sessions",
|
||||||
|
nil, nil,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ServerCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- c.BuildInfo
|
||||||
|
ch <- c.ServerConns
|
||||||
|
ch <- c.ServerRoutes
|
||||||
|
ch <- c.ServerPeers
|
||||||
|
ch <- c.SshProxySessions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ServerCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.BuildInfo,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1,
|
||||||
|
runtime.GOARCH,
|
||||||
|
runtime.GOOS,
|
||||||
|
runtime.Version(),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ServerConns,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.server.stats.conns.Load()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ServerRoutes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.server.stats.routes.Load()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ServerPeers,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.server.stats.peers.Load()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.SshProxySessions,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(c.server.stats.ssh_proxy_sessions.Load()),
|
||||||
|
)
|
||||||
|
}
|
@ -184,7 +184,7 @@ func mutate_proxy_req_headers(req *http.Request, newreq *http.Request, path_pref
|
|||||||
return upgrade_required
|
return upgrade_required
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *server_proxy) GetId() string {
|
func (pxy *server_proxy) Id() string {
|
||||||
return pxy.id
|
return pxy.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
server.go
33
server.go
@ -18,9 +18,10 @@ import "unsafe"
|
|||||||
import "golang.org/x/net/websocket"
|
import "golang.org/x/net/websocket"
|
||||||
import "google.golang.org/grpc"
|
import "google.golang.org/grpc"
|
||||||
import "google.golang.org/grpc/credentials"
|
import "google.golang.org/grpc/credentials"
|
||||||
//import "google.golang.org/grpc/metadata"
|
|
||||||
import "google.golang.org/grpc/peer"
|
import "google.golang.org/grpc/peer"
|
||||||
import "google.golang.org/grpc/stats"
|
import "google.golang.org/grpc/stats"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
import "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
||||||
const PTS_LIMIT int = 16384
|
const PTS_LIMIT int = 16384
|
||||||
const CTS_LIMIT int = 16384
|
const CTS_LIMIT int = 16384
|
||||||
@ -42,6 +43,9 @@ type ServerWpxResponseTransformer func(r *ServerRouteProxyInfo, resp *http.Respo
|
|||||||
type ServerWpxForeignPortProxyMaker func(wpx_type string, port_id string) (*ServerRouteProxyInfo, error)
|
type ServerWpxForeignPortProxyMaker func(wpx_type string, port_id string) (*ServerRouteProxyInfo, error)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
UnimplementedHoduServer
|
||||||
|
Named
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctx_cancel context.CancelFunc
|
ctx_cancel context.CancelFunc
|
||||||
pxytlscfg *tls.Config
|
pxytlscfg *tls.Config
|
||||||
@ -88,6 +92,7 @@ type Server struct {
|
|||||||
svc_port_mtx sync.Mutex
|
svc_port_mtx sync.Mutex
|
||||||
svc_port_map ServerSvcPortMap
|
svc_port_map ServerSvcPortMap
|
||||||
|
|
||||||
|
promreg *prometheus.Registry
|
||||||
stats struct {
|
stats struct {
|
||||||
conns atomic.Int64
|
conns atomic.Int64
|
||||||
routes atomic.Int64
|
routes atomic.Int64
|
||||||
@ -98,8 +103,6 @@ type Server struct {
|
|||||||
wpx_resp_tf ServerWpxResponseTransformer
|
wpx_resp_tf ServerWpxResponseTransformer
|
||||||
wpx_foreign_port_proxy_maker ServerWpxForeignPortProxyMaker
|
wpx_foreign_port_proxy_maker ServerWpxForeignPortProxyMaker
|
||||||
xterm_html string
|
xterm_html string
|
||||||
|
|
||||||
UnimplementedHoduServer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// connection from client.
|
// connection from client.
|
||||||
@ -927,7 +930,7 @@ func (hlw *server_http_log_writer) Write(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServerHttpHandler interface {
|
type ServerHttpHandler interface {
|
||||||
GetId() string
|
Id() string
|
||||||
ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error)
|
ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,15 +957,15 @@ func (s *Server) wrap_http_handler(handler ServerHttpHandler) http.Handler {
|
|||||||
|
|
||||||
if status_code > 0 {
|
if status_code > 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.log.Write(handler.GetId(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
|
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
|
||||||
} else {
|
} else {
|
||||||
s.log.Write(handler.GetId(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
|
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, pxytlscfg *tls.Config, wpxtlscfg *tls.Config, rpc_max int, peer_max int) (*Server, error) {
|
func NewServer(ctx context.Context, name string, logger Logger, ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, pxytlscfg *tls.Config, wpxtlscfg *tls.Config, rpc_max int, peer_max int) (*Server, error) {
|
||||||
var s Server
|
var s Server
|
||||||
var l *net.TCPListener
|
var l *net.TCPListener
|
||||||
var rpcaddr *net.TCPAddr
|
var rpcaddr *net.TCPAddr
|
||||||
@ -978,6 +981,7 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.ctx, s.ctx_cancel = context.WithCancel(ctx)
|
s.ctx, s.ctx_cancel = context.WithCancel(ctx)
|
||||||
|
s.name = name
|
||||||
s.log = logger
|
s.log = logger
|
||||||
/* create the specified number of listeners */
|
/* create the specified number of listeners */
|
||||||
s.rpc = make([]*net.TCPListener, 0)
|
s.rpc = make([]*net.TCPListener, 0)
|
||||||
@ -1043,6 +1047,13 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs
|
|||||||
s.ctl_mux.Handle(s.ctl_prefix + "/_ctl/stats",
|
s.ctl_mux.Handle(s.ctl_prefix + "/_ctl/stats",
|
||||||
s.wrap_http_handler(&server_ctl_stats{server_ctl{s: &s, id: HS_ID_CTL}}))
|
s.wrap_http_handler(&server_ctl_stats{server_ctl{s: &s, id: HS_ID_CTL}}))
|
||||||
|
|
||||||
|
// TODO: make this optional. add this endpoint only if it's enabled...
|
||||||
|
s.promreg = prometheus.NewRegistry()
|
||||||
|
s.promreg.MustRegister(prometheus.NewGoCollector())
|
||||||
|
s.promreg.MustRegister(NewServerCollector(&s))
|
||||||
|
s.ctl_mux.Handle(s.ctl_prefix + "/_ctl/metrics",
|
||||||
|
promhttp.HandlerFor(s.promreg, promhttp.HandlerOpts{ EnableOpenMetrics: true }))
|
||||||
|
|
||||||
s.ctl_addr = make([]string, len(ctl_addrs))
|
s.ctl_addr = make([]string, len(ctl_addrs))
|
||||||
s.ctl = make([]*http.Server, len(ctl_addrs))
|
s.ctl = make([]*http.Server, len(ctl_addrs))
|
||||||
copy(s.ctl_addr, ctl_addrs)
|
copy(s.ctl_addr, ctl_addrs)
|
||||||
@ -1660,3 +1671,11 @@ func (s *Server) WriteLog(id string, level LogLevel, fmtstr string, args ...inte
|
|||||||
func (s *Server) AddCtlHandler(path string, handler ServerHttpHandler) {
|
func (s *Server) AddCtlHandler(path string, handler ServerHttpHandler) {
|
||||||
s.ctl_mux.Handle(s.ctl_prefix + "/_ctl" + path, s.wrap_http_handler(handler))
|
s.ctl_mux.Handle(s.ctl_prefix + "/_ctl" + path, s.wrap_http_handler(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddCtlMetricsCollector(col prometheus.Collector) error {
|
||||||
|
return s.promreg.Register(col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveCtlMetricsCollector(col prometheus.Collector) bool {
|
||||||
|
return s.promreg.Unregister(col)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user