api: enrich provider statistifcs

This commit is contained in:
yusing 2025-01-15 09:06:54 +08:00
parent 2af2346e35
commit 04e118c081
7 changed files with 97 additions and 32 deletions

View file

@ -25,21 +25,22 @@ func (cfg *Config) DumpProviders() map[string]*provider.Provider {
} }
func (cfg *Config) Statistics() map[string]any { func (cfg *Config) Statistics() map[string]any {
nTotalStreams := 0 var rps, streams provider.RouteStats
nTotalRPs := 0 var total uint16
providerStats := make(map[string]provider.ProviderStats) providerStats := make(map[string]provider.ProviderStats)
cfg.providers.RangeAll(func(_ string, p *provider.Provider) { cfg.providers.RangeAll(func(_ string, p *provider.Provider) {
stats := p.Statistics() stats := p.Statistics()
providerStats[p.ShortName()] = stats providerStats[p.ShortName()] = stats
rps.AddOther(stats.RPs)
nTotalRPs += stats.NumRPs streams.AddOther(stats.Streams)
nTotalStreams += stats.NumStreams total += stats.RPs.Total + stats.Streams.Total
}) })
return map[string]any{ return map[string]any{
"num_total_streams": nTotalStreams, "total": total,
"num_total_reverse_proxies": nTotalRPs, "reverse_proxies": rps,
"streams": streams,
"providers": providerStats, "providers": providerStats,
} }
} }

View file

@ -180,6 +180,13 @@ func (r *HTTPRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.handler.ServeHTTP(w, req) r.handler.ServeHTTP(w, req)
} }
func (r *HTTPRoute) Health() health.Status {
if r.HealthMon != nil {
return r.HealthMon.Status()
}
return health.StatusUnknown
}
func (r *HTTPRoute) addToLoadBalancer(parent task.Parent) { func (r *HTTPRoute) addToLoadBalancer(parent task.Parent) {
var lb *loadbalancer.LoadBalancer var lb *loadbalancer.LoadBalancer
cfg := r.Raw.LoadBalance cfg := r.Raw.LoadBalance

View file

@ -10,7 +10,6 @@ import (
E "github.com/yusing/go-proxy/internal/error" E "github.com/yusing/go-proxy/internal/error"
R "github.com/yusing/go-proxy/internal/route" R "github.com/yusing/go-proxy/internal/route"
"github.com/yusing/go-proxy/internal/route/provider/types" "github.com/yusing/go-proxy/internal/route/provider/types"
route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/task"
W "github.com/yusing/go-proxy/internal/watcher" W "github.com/yusing/go-proxy/internal/watcher"
"github.com/yusing/go-proxy/internal/watcher/events" "github.com/yusing/go-proxy/internal/watcher/events"
@ -33,11 +32,6 @@ type (
NewWatcher() W.Watcher NewWatcher() W.Watcher
Logger() *zerolog.Logger Logger() *zerolog.Logger
} }
ProviderStats struct {
NumRPs int `json:"num_reverse_proxies"`
NumStreams int `json:"num_streams"`
Type types.ProviderType `json:"type"`
}
) )
const ( const (
@ -154,21 +148,3 @@ func (p *Provider) LoadRoutes() E.Error {
func (p *Provider) NumRoutes() int { func (p *Provider) NumRoutes() int {
return p.routes.Size() return p.routes.Size()
} }
func (p *Provider) Statistics() ProviderStats {
numRPs := 0
numStreams := 0
p.routes.RangeAll(func(_ string, r *R.Route) {
switch r.Type {
case route.RouteTypeReverseProxy:
numRPs++
case route.RouteTypeStream:
numStreams++
}
})
return ProviderStats{
NumRPs: numRPs,
NumStreams: numStreams,
Type: p.t,
}
}

View file

@ -0,0 +1,68 @@
package provider
import (
R "github.com/yusing/go-proxy/internal/route"
"github.com/yusing/go-proxy/internal/route/provider/types"
route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/watcher/health"
)
type (
RouteStats struct {
Total uint16 `json:"total"`
NumHealthy uint16 `json:"healthy"`
NumUnhealthy uint16 `json:"unhealthy"`
NumNapping uint16 `json:"napping"`
NumError uint16 `json:"error"`
NumUnknown uint16 `json:"unknown"`
}
ProviderStats struct {
Total uint16 `json:"total"`
RPs RouteStats `json:"reverse_proxies"`
Streams RouteStats `json:"streams"`
Type types.ProviderType `json:"type"`
}
)
func (stats *RouteStats) Add(r *R.Route) {
stats.Total++
switch r.Health() {
case health.StatusHealthy:
stats.NumHealthy++
case health.StatusUnhealthy:
stats.NumUnhealthy++
case health.StatusNapping:
stats.NumNapping++
case health.StatusError:
stats.NumError++
default:
stats.NumUnknown++
}
}
func (stats *RouteStats) AddOther(other RouteStats) {
stats.Total += other.Total
stats.NumHealthy += other.NumHealthy
stats.NumUnhealthy += other.NumUnhealthy
stats.NumNapping += other.NumNapping
stats.NumError += other.NumError
stats.NumUnknown += other.NumUnknown
}
func (p *Provider) Statistics() ProviderStats {
var rps, streams RouteStats
p.routes.RangeAll(func(_ string, r *R.Route) {
switch r.Type {
case route.RouteTypeReverseProxy:
rps.Add(r)
case route.RouteTypeStream:
streams.Add(r)
}
})
return ProviderStats{
Total: rps.Total + streams.Total,
RPs: rps,
Streams: streams,
Type: p.t,
}
}

View file

@ -11,6 +11,7 @@ import (
"github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/task"
U "github.com/yusing/go-proxy/internal/utils" U "github.com/yusing/go-proxy/internal/utils"
F "github.com/yusing/go-proxy/internal/utils/functional" F "github.com/yusing/go-proxy/internal/utils/functional"
"github.com/yusing/go-proxy/internal/watcher/health"
) )
type ( type (
@ -28,6 +29,7 @@ type (
task.TaskFinisher task.TaskFinisher
String() string String() string
TargetURL() url.URL TargetURL() url.URL
Health() health.Status
} }
RawEntry = types.RawEntry RawEntry = types.RawEntry
RawEntries = types.RawEntries RawEntries = types.RawEntries

View file

@ -116,6 +116,14 @@ func (r *StreamRoute) Finish(reason any) {
r.task.Finish(reason) r.task.Finish(reason)
} }
func (r *StreamRoute) Health() health.Status {
if r.HealthMon != nil {
return r.HealthMon.Status()
}
return health.StatusUnknown
}
func (r *StreamRoute) acceptConnections() { func (r *StreamRoute) acceptConnections() {
defer r.task.Finish("listener closed") defer r.task.Finish("listener closed")

View file

@ -4,15 +4,18 @@ import (
"net/http" "net/http"
net "github.com/yusing/go-proxy/internal/net/types" net "github.com/yusing/go-proxy/internal/net/types"
"github.com/yusing/go-proxy/internal/watcher/health"
) )
type ( type (
HTTPRoute interface { HTTPRoute interface {
Entry Entry
http.Handler http.Handler
Health() health.Status
} }
StreamRoute interface { StreamRoute interface {
Entry Entry
net.Stream net.Stream
Health() health.Status
} }
) )