Compare commits

..

No commits in common. "30cc92870515af08cbe2647d598b3ba5c697d9cf" and "abc73f2ca2b7aeaef172796da382e13c3d69ce8c" have entirely different histories.

14 changed files with 74 additions and 393 deletions

View File

@ -1,9 +1,6 @@
package bypass package bypass
import ( import "context"
"context"
"slices"
)
type Options struct { type Options struct {
Host string Host string
@ -27,7 +24,6 @@ func WithPathOption(path string) Option {
// Bypass is a filter of address (IP or domain). // Bypass is a filter of address (IP or domain).
type Bypass interface { type Bypass interface {
// Contains reports whether the bypass includes addr. // Contains reports whether the bypass includes addr.
IsWhitelist() bool
Contains(ctx context.Context, network, addr string, opts ...Option) bool Contains(ctx context.Context, network, addr string, opts ...Option) bool
} }
@ -42,33 +38,10 @@ func BypassGroup(bypasses ...Bypass) Bypass {
} }
func (p *bypassGroup) Contains(ctx context.Context, network, addr string, opts ...Option) bool { func (p *bypassGroup) Contains(ctx context.Context, network, addr string, opts ...Option) bool {
var whitelist, blacklist []bool
for _, bypass := range p.bypasses { for _, bypass := range p.bypasses {
result := bypass.Contains(ctx, network, addr, opts...) if bypass != nil && bypass.Contains(ctx, network, addr, opts...) {
if bypass.IsWhitelist() { return true
whitelist = append(whitelist, result)
} else {
blacklist = append(blacklist, result)
} }
} }
status := false
if len(whitelist) > 0 {
if slices.Contains(whitelist, false) {
status = false
} else {
status = true
}
}
if !status && len(blacklist) > 0 {
if slices.Contains(blacklist, true) {
status = true
} else {
status = false
}
}
return status
}
func (p *bypassGroup) IsWhitelist() bool {
return false return false
} }

View File

@ -1,8 +1,6 @@
package chain package chain
import ( import (
"regexp"
"github.com/go-gost/core/auth" "github.com/go-gost/core/auth"
"github.com/go-gost/core/bypass" "github.com/go-gost/core/bypass"
"github.com/go-gost/core/hosts" "github.com/go-gost/core/hosts"
@ -11,22 +9,9 @@ import (
"github.com/go-gost/core/selector" "github.com/go-gost/core/selector"
) )
type NodeFilterSettings struct {
Protocol string
Host string
Path string
}
type HTTPURLRewriteSetting struct {
Pattern *regexp.Regexp
Replacement string
}
type HTTPNodeSettings struct { type HTTPNodeSettings struct {
Host string Host string
Header map[string]string Header map[string]string
Auther auth.Authenticator
Rewrite []HTTPURLRewriteSetting
} }
type TLSNodeSettings struct { type TLSNodeSettings struct {
@ -40,15 +25,18 @@ type TLSNodeSettings struct {
} }
type NodeOptions struct { type NodeOptions struct {
Network string
Transport *Transport Transport *Transport
Bypass bypass.Bypass Bypass bypass.Bypass
Resolver resolver.Resolver Resolver resolver.Resolver
HostMapper hosts.HostMapper HostMapper hosts.HostMapper
Filter *NodeFilterSettings Metadata metadata.Metadata
Host string
Network string
Protocol string
Path string
HTTP *HTTPNodeSettings HTTP *HTTPNodeSettings
TLS *TLSNodeSettings TLS *TLSNodeSettings
Metadata metadata.Metadata Auther auth.Authenticator
} }
type NodeOption func(*NodeOptions) type NodeOption func(*NodeOptions)
@ -77,15 +65,33 @@ func HostMapperNodeOption(m hosts.HostMapper) NodeOption {
} }
} }
func HostNodeOption(host string) NodeOption {
return func(o *NodeOptions) {
o.Host = host
}
}
func NetworkNodeOption(network string) NodeOption { func NetworkNodeOption(network string) NodeOption {
return func(o *NodeOptions) { return func(o *NodeOptions) {
o.Network = network o.Network = network
} }
} }
func NodeFilterOption(filter *NodeFilterSettings) NodeOption { func ProtocolNodeOption(protocol string) NodeOption {
return func(o *NodeOptions) { return func(o *NodeOptions) {
o.Filter = filter o.Protocol = protocol
}
}
func PathNodeOption(path string) NodeOption {
return func(o *NodeOptions) {
o.Path = path
}
}
func MetadataNodeOption(md metadata.Metadata) NodeOption {
return func(o *NodeOptions) {
o.Metadata = md
} }
} }
@ -101,9 +107,9 @@ func TLSNodeOption(tlsSettings *TLSNodeSettings) NodeOption {
} }
} }
func MetadataNodeOption(md metadata.Metadata) NodeOption { func AutherNodeOption(auther auth.Authenticator) NodeOption {
return func(o *NodeOptions) { return func(o *NodeOptions) {
o.Metadata = md o.Auther = auther
} }
} }

View File

@ -36,8 +36,8 @@ func (*route) Dial(ctx context.Context, network, address string, opts ...DialOpt
} }
netd := dialer.NetDialer{ netd := dialer.NetDialer{
Timeout: options.Timeout,
Interface: options.Interface, Interface: options.Interface,
Netns: options.Netns,
Logger: options.Logger, Logger: options.Logger,
} }
if options.SockOpts != nil { if options.SockOpts != nil {
@ -93,23 +93,23 @@ func (r *route) Nodes() []*Node {
} }
type DialOptions struct { type DialOptions struct {
Timeout time.Duration
Interface string Interface string
Netns string
SockOpts *SockOpts SockOpts *SockOpts
Logger logger.Logger Logger logger.Logger
} }
type DialOption func(opts *DialOptions) type DialOption func(opts *DialOptions)
func InterfaceDialOption(ifName string) DialOption { func TimeoutDialOption(d time.Duration) DialOption {
return func(opts *DialOptions) { return func(opts *DialOptions) {
opts.Interface = ifName opts.Timeout = d
} }
} }
func NetnsDialOption(netns string) DialOption { func InterfaceDialOption(ifName string) DialOption {
return func(opts *DialOptions) { return func(opts *DialOptions) {
opts.Netns = netns opts.Interface = ifName
} }
} }

View File

@ -21,7 +21,6 @@ type RouterOptions struct {
Retries int Retries int
Timeout time.Duration Timeout time.Duration
IfceName string IfceName string
Netns string
SockOpts *SockOpts SockOpts *SockOpts
Chain Chainer Chain Chainer
Resolver resolver.Resolver Resolver resolver.Resolver
@ -38,12 +37,6 @@ func InterfaceRouterOption(ifceName string) RouterOption {
} }
} }
func NetnsRouterOption(netns string) RouterOption {
return func(o *RouterOptions) {
o.Netns = netns
}
}
func SockOptsRouterOption(so *SockOpts) RouterOption { func SockOptsRouterOption(so *SockOpts) RouterOption {
return func(o *RouterOptions) { return func(o *RouterOptions) {
o.SockOpts = so o.SockOpts = so
@ -103,10 +96,6 @@ func NewRouter(opts ...RouterOption) *Router {
opt(&r.options) opt(&r.options)
} }
} }
if r.options.Timeout == 0 {
r.options.Timeout = 15 * time.Second
}
if r.options.Logger == nil { if r.options.Logger == nil {
r.options.Logger = logger.Default().WithFields(map[string]any{"kind": "router"}) r.options.Logger = logger.Default().WithFields(map[string]any{"kind": "router"})
} }
@ -121,12 +110,6 @@ func (r *Router) Options() *RouterOptions {
} }
func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) { func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
if r.options.Timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, r.options.Timeout)
defer cancel()
}
host := address host := address
if h, _, _ := net.SplitHostPort(address); h != "" { if h, _, _ := net.SplitHostPort(address); h != "" {
host = h host = h
@ -198,9 +181,9 @@ func (r *Router) dial(ctx context.Context, network, address string) (conn net.Co
} }
conn, err = route.Dial(ctx, network, ipAddr, conn, err = route.Dial(ctx, network, ipAddr,
InterfaceDialOption(r.options.IfceName), InterfaceDialOption(r.options.IfceName),
NetnsDialOption(r.options.Netns),
SockOptsDialOption(r.options.SockOpts), SockOptsDialOption(r.options.SockOpts),
LoggerDialOption(r.options.Logger), LoggerDialOption(r.options.Logger),
TimeoutDialOption(r.options.Timeout),
) )
if err == nil { if err == nil {
break break
@ -212,12 +195,6 @@ func (r *Router) dial(ctx context.Context, network, address string) (conn net.Co
} }
func (r *Router) Bind(ctx context.Context, network, address string, opts ...BindOption) (ln net.Listener, err error) { func (r *Router) Bind(ctx context.Context, network, address string, opts ...BindOption) (ln net.Listener, err error) {
if r.options.Timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, r.options.Timeout)
defer cancel()
}
count := r.options.Retries + 1 count := r.options.Retries + 1
if count <= 0 { if count <= 0 {
count = 1 count = 1

View File

@ -3,6 +3,7 @@ package chain
import ( import (
"context" "context"
"net" "net"
"time"
net_dialer "github.com/go-gost/core/common/net/dialer" net_dialer "github.com/go-gost/core/common/net/dialer"
"github.com/go-gost/core/connector" "github.com/go-gost/core/connector"
@ -12,9 +13,9 @@ import (
type TransportOptions struct { type TransportOptions struct {
Addr string Addr string
IfceName string IfceName string
Netns string
SockOpts *SockOpts SockOpts *SockOpts
Route Route Route Route
Timeout time.Duration
} }
type TransportOption func(*TransportOptions) type TransportOption func(*TransportOptions)
@ -31,12 +32,6 @@ func InterfaceTransportOption(ifceName string) TransportOption {
} }
} }
func NetnsTransportOption(netns string) TransportOption {
return func(o *TransportOptions) {
o.Netns = netns
}
}
func SockOptsTransportOption(so *SockOpts) TransportOption { func SockOptsTransportOption(so *SockOpts) TransportOption {
return func(o *TransportOptions) { return func(o *TransportOptions) {
o.SockOpts = so o.SockOpts = so
@ -49,6 +44,12 @@ func RouteTransportOption(route Route) TransportOption {
} }
} }
func TimeoutTransportOption(timeout time.Duration) TransportOption {
return func(o *TransportOptions) {
o.Timeout = timeout
}
}
type Transport struct { type Transport struct {
dialer dialer.Dialer dialer dialer.Dialer
connector connector.Connector connector connector.Connector
@ -72,7 +73,7 @@ func NewTransport(d dialer.Dialer, c connector.Connector, opts ...TransportOptio
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) { func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
netd := &net_dialer.NetDialer{ netd := &net_dialer.NetDialer{
Interface: tr.options.IfceName, Interface: tr.options.IfceName,
Netns: tr.options.Netns, Timeout: tr.options.Timeout,
} }
if tr.options.SockOpts != nil { if tr.options.SockOpts != nil {
netd.Mark = tr.options.SockOpts.Mark netd.Mark = tr.options.SockOpts.Mark
@ -107,7 +108,7 @@ func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, er
func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) { func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
netd := &net_dialer.NetDialer{ netd := &net_dialer.NetDialer{
Interface: tr.options.IfceName, Interface: tr.options.IfceName,
Netns: tr.options.Netns, Timeout: tr.options.Timeout,
} }
if tr.options.SockOpts != nil { if tr.options.SockOpts != nil {
netd.Mark = tr.options.SockOpts.Mark netd.Mark = tr.options.SockOpts.Mark

View File

@ -4,14 +4,12 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"runtime"
"strings" "strings"
"syscall" "syscall"
"time" "time"
xnet "github.com/go-gost/core/common/net" xnet "github.com/go-gost/core/common/net"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
"github.com/vishvananda/netns"
) )
const ( const (
@ -24,8 +22,8 @@ var (
type NetDialer struct { type NetDialer struct {
Interface string Interface string
Netns string
Mark int Mark int
Timeout time.Duration
DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
Logger logger.Logger Logger logger.Logger
} }
@ -35,36 +33,20 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (conn net.Co
d = DefaultNetDialer d = DefaultNetDialer
} }
log := d.Logger timeout := d.Timeout
if log == nil { if timeout <= 0 {
log = logger.Default() timeout = DefaultTimeout
}
if d.Netns != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
originNs, err := netns.Get()
if err != nil {
return nil, fmt.Errorf("netns.Get(): %v", err)
}
defer netns.Set(originNs)
ns, err := netns.GetFromName(d.Netns)
if err != nil {
return nil, fmt.Errorf("netns.GetFromName(%s): %v", d.Netns, err)
}
defer ns.Close()
if err := netns.Set(ns); err != nil {
return nil, fmt.Errorf("netns.Set(%s): %v", d.Netns, err)
}
} }
if d.DialFunc != nil { if d.DialFunc != nil {
return d.DialFunc(ctx, network, addr) return d.DialFunc(ctx, network, addr)
} }
log := d.Logger
if log == nil {
log = logger.Default()
}
switch network { switch network {
case "unix": case "unix":
netd := net.Dialer{} netd := net.Dialer{}
@ -72,6 +54,7 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (conn net.Co
default: default:
} }
deadline := time.Now().Add(timeout)
ifces := strings.Split(d.Interface, ",") ifces := strings.Split(d.Interface, ",")
for _, ifce := range ifces { for _, ifce := range ifces {
strict := strings.HasSuffix(ifce, "!") strict := strings.HasSuffix(ifce, "!")
@ -84,7 +67,7 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (conn net.Co
} }
for _, ifAddr := range ifAddrs { for _, ifAddr := range ifAddrs {
conn, err = d.dialOnce(ctx, network, addr, ifceName, ifAddr, log) conn, err = d.dialOnce(ctx, network, addr, ifceName, ifAddr, deadline, log)
if err == nil { if err == nil {
return return
} }
@ -96,13 +79,17 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (conn net.Co
!strings.Contains(err.Error(), "mismatched local address type") { !strings.Contains(err.Error(), "mismatched local address type") {
return return
} }
if time.Until(deadline) < 0 {
return
}
} }
} }
return return
} }
func (d *NetDialer) dialOnce(ctx context.Context, network, addr, ifceName string, ifAddr net.Addr, log logger.Logger) (net.Conn, error) { func (d *NetDialer) dialOnce(ctx context.Context, network, addr, ifceName string, ifAddr net.Addr, deadline time.Time, log logger.Logger) (net.Conn, error) {
if ifceName != "" { if ifceName != "" {
log.Debugf("interface: %s %v/%s", ifceName, ifAddr, network) log.Debugf("interface: %s %v/%s", ifceName, ifAddr, network)
} }
@ -146,6 +133,7 @@ func (d *NetDialer) dialOnce(ctx context.Context, network, addr, ifceName string
return nil, fmt.Errorf("dial: unsupported network %s", network) return nil, fmt.Errorf("dial: unsupported network %s", network)
} }
netd := net.Dialer{ netd := net.Dialer{
Deadline: deadline,
LocalAddr: ifAddr, LocalAddr: ifAddr,
Control: func(network, address string, c syscall.RawConn) error { Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) { return c.Control(func(fd uintptr) {
@ -162,10 +150,5 @@ func (d *NetDialer) dialOnce(ctx context.Context, network, addr, ifceName string
}) })
}, },
} }
if d.Netns != "" {
// https://github.com/golang/go/issues/44922#issuecomment-796645858
netd.FallbackDelay = -1
}
return netd.DialContext(ctx, network, addr) return netd.DialContext(ctx, network, addr)
} }

9
go.mod
View File

@ -1,10 +1,5 @@
module github.com/go-gost/core module github.com/go-gost/core
go 1.22 go 1.18
toolchain go1.22.2 require golang.org/x/sys v0.12.0
require (
github.com/vishvananda/netns v0.0.4
golang.org/x/sys v0.21.0
)

6
go.sum
View File

@ -1,4 +1,2 @@
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -11,7 +11,6 @@ import (
"github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/limiter/traffic"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
"github.com/go-gost/core/metadata" "github.com/go-gost/core/metadata"
"github.com/go-gost/core/observer"
) )
type Options struct { type Options struct {
@ -23,9 +22,7 @@ type Options struct {
Limiter traffic.TrafficLimiter Limiter traffic.TrafficLimiter
TLSConfig *tls.Config TLSConfig *tls.Config
Logger logger.Logger Logger logger.Logger
Observer observer.Observer
Service string Service string
Netns string
} }
type Option func(opts *Options) type Option func(opts *Options)
@ -78,24 +75,12 @@ func LoggerOption(logger logger.Logger) Option {
} }
} }
func ObserverOption(observer observer.Observer) Option {
return func(opts *Options) {
opts.Observer = observer
}
}
func ServiceOption(service string) Option { func ServiceOption(service string) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Service = service opts.Service = service
} }
} }
func NetnsOption(netns string) Option {
return func(opts *Options) {
opts.Netns = netns
}
}
type HandleOptions struct { type HandleOptions struct {
Metadata metadata.Metadata Metadata metadata.Metadata
} }

View File

@ -10,7 +10,6 @@ import (
"github.com/go-gost/core/limiter/conn" "github.com/go-gost/core/limiter/conn"
"github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/limiter/traffic"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
"github.com/go-gost/core/observer/stats"
) )
type Options struct { type Options struct {
@ -22,12 +21,9 @@ type Options struct {
TrafficLimiter traffic.TrafficLimiter TrafficLimiter traffic.TrafficLimiter
ConnLimiter conn.ConnLimiter ConnLimiter conn.ConnLimiter
Chain chain.Chainer Chain chain.Chainer
Stats *stats.Stats
Logger logger.Logger Logger logger.Logger
Service string Service string
ProxyProtocol int ProxyProtocol int
Netns string
Router *chain.Router
} }
type Option func(opts *Options) type Option func(opts *Options)
@ -74,9 +70,9 @@ func ConnLimiterOption(limiter conn.ConnLimiter) Option {
} }
} }
func StatsOption(stats *stats.Stats) Option { func ChainOption(chain chain.Chainer) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Stats = stats opts.Chain = chain
} }
} }
@ -97,15 +93,3 @@ func ProxyProtocolOption(ppv int) Option {
opts.ProxyProtocol = ppv opts.ProxyProtocol = ppv
} }
} }
func NetnsOption(netns string) Option {
return func(opts *Options) {
opts.Netns = netns
}
}
func RouterOption(router *chain.Router) Option {
return func(opts *Options) {
opts.Router = router
}
}

View File

@ -55,109 +55,3 @@ func Default() Logger {
func SetDefault(logger Logger) { func SetDefault(logger Logger) {
defaultLogger = logger defaultLogger = logger
} }
type loggerGroup struct {
loggers []Logger
}
func LoggerGroup(loggers ...Logger) Logger {
return &loggerGroup{
loggers: loggers,
}
}
func (l *loggerGroup) WithFields(m map[string]any) Logger {
lg := &loggerGroup{}
for i := range l.loggers {
lg.loggers = append(lg.loggers, l.loggers[i].WithFields(m))
}
return lg
}
func (l *loggerGroup) Trace(args ...any) {
for _, lg := range l.loggers {
lg.Trace(args...)
}
}
func (l *loggerGroup) Tracef(format string, args ...any) {
for _, lg := range l.loggers {
lg.Tracef(format, args...)
}
}
func (l *loggerGroup) Debug(args ...any) {
for _, lg := range l.loggers {
lg.Debug(args...)
}
}
func (l *loggerGroup) Debugf(format string, args ...any) {
for _, lg := range l.loggers {
lg.Debugf(format, args...)
}
}
func (l *loggerGroup) Info(args ...any) {
for _, lg := range l.loggers {
lg.Info(args...)
}
}
func (l *loggerGroup) Infof(format string, args ...any) {
for _, lg := range l.loggers {
lg.Infof(format, args...)
}
}
func (l *loggerGroup) Warn(args ...any) {
for _, lg := range l.loggers {
lg.Warn(args...)
}
}
func (l *loggerGroup) Warnf(format string, args ...any) {
for _, lg := range l.loggers {
lg.Warnf(format, args...)
}
}
func (l *loggerGroup) Error(args ...any) {
for _, lg := range l.loggers {
lg.Error(args...)
}
}
func (l *loggerGroup) Errorf(format string, args ...any) {
for _, lg := range l.loggers {
lg.Errorf(format, args...)
}
}
func (l *loggerGroup) Fatal(args ...any) {
for _, lg := range l.loggers {
lg.Fatal(args...)
}
}
func (l *loggerGroup) Fatalf(format string, args ...any) {
for _, lg := range l.loggers {
lg.Fatalf(format, args...)
}
}
func (l *loggerGroup) GetLevel() LogLevel {
for _, lg := range l.loggers {
return lg.GetLevel()
}
return InfoLevel
}
func (l *loggerGroup) IsLevelEnabled(level LogLevel) bool {
for _, lg := range l.loggers {
if lg.IsLevelEnabled(level) {
return true
}
}
return false
}

View File

@ -1,22 +0,0 @@
package observer
import "context"
type Options struct{}
type Option func(opts *Options)
type Observer interface {
Observe(ctx context.Context, events []Event, opts ...Option) error
}
type EventType string
const (
EventStatus EventType = "status"
EventStats EventType = "stats"
)
type Event interface {
Type() EventType
}

View File

@ -1,93 +0,0 @@
package stats
import (
"sync/atomic"
"github.com/go-gost/core/observer"
)
type Kind int
const (
KindTotalConns Kind = 1
KindCurrentConns Kind = 2
KindInputBytes Kind = 3
KindOutputBytes Kind = 4
KindTotalErrs Kind = 5
)
type Stats struct {
updated atomic.Bool
totalConns atomic.Uint64
currentConns atomic.Int64
inputBytes atomic.Uint64
outputBytes atomic.Uint64
totalErrs atomic.Uint64
}
func (s *Stats) Add(kind Kind, n int64) {
if s == nil {
return
}
switch kind {
case KindTotalConns:
if n > 0 {
s.totalConns.Add(uint64(n))
}
case KindCurrentConns:
s.currentConns.Add(n)
case KindInputBytes:
if n > 0 {
s.inputBytes.Add(uint64(n))
}
case KindOutputBytes:
if n > 0 {
s.outputBytes.Add(uint64(n))
}
case KindTotalErrs:
if n > 0 {
s.totalErrs.Add(uint64(n))
}
}
s.updated.Store(true)
}
func (s *Stats) Get(kind Kind) uint64 {
if s == nil {
return 0
}
switch kind {
case KindTotalConns:
return s.totalConns.Load()
case KindCurrentConns:
return uint64(s.currentConns.Load())
case KindInputBytes:
return s.inputBytes.Load()
case KindOutputBytes:
return s.outputBytes.Load()
case KindTotalErrs:
return s.totalErrs.Load()
}
return 0
}
func (s *Stats) IsUpdated() bool {
return s.updated.Swap(false)
}
type StatsEvent struct {
Kind string
Service string
Client string
TotalConns uint64
CurrentConns uint64
InputBytes uint64
OutputBytes uint64
TotalErrs uint64
}
func (StatsEvent) Type() observer.EventType {
return observer.EventStats
}

View File

@ -10,7 +10,7 @@ type RecordOptions struct {
type RecordOption func(opts *RecordOptions) type RecordOption func(opts *RecordOptions)
func MetadataRecordOption(md any) RecordOption { func MetadataReocrdOption(md any) RecordOption {
return func(opts *RecordOptions) { return func(opts *RecordOptions) {
opts.Metadata = md opts.Metadata = md
} }