mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 11:54:01 +03:00
Add new stats metric
This commit is contained in:
+2
-2
@@ -16,9 +16,9 @@ func Init() {
|
|||||||
initOnce.Do(func() {
|
initOnce.Do(func() {
|
||||||
c, err := bigcache.NewBigCache(bigcache.Config{
|
c, err := bigcache.NewBigCache(bigcache.Config{
|
||||||
Shards: 1024,
|
Shards: 1024,
|
||||||
LifeWindow: config.C.AntiReplay.EvictionTime,
|
LifeWindow: config.C.AntiReplayEvictionTime,
|
||||||
Hasher: hasher{},
|
Hasher: hasher{},
|
||||||
HardMaxCacheSize: config.C.AntiReplay.MaxSize,
|
HardMaxCacheSize: config.C.AntiReplayMaxSize,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
+2
-2
@@ -43,7 +43,7 @@ func Proxy() error {
|
|||||||
if err := config.InitPublicAddress(ctx); err != nil {
|
if err := config.InitPublicAddress(ctx); err != nil {
|
||||||
Fatal(err)
|
Fatal(err)
|
||||||
}
|
}
|
||||||
zap.S().Debugw("Configuration", "config", config.C.Printable())
|
zap.S().Debugw("Configuration", "config", config.Printable())
|
||||||
|
|
||||||
if len(config.C.AdTag) > 0 {
|
if len(config.C.AdTag) > 0 {
|
||||||
zap.S().Infow("Use middle proxy connection to Telegram")
|
zap.S().Infow("Use middle proxy connection to Telegram")
|
||||||
@@ -67,7 +67,7 @@ func Proxy() error {
|
|||||||
}
|
}
|
||||||
telegram.MiddleInit()
|
telegram.MiddleInit()
|
||||||
|
|
||||||
proxyListener, err := net.Listen("tcp", config.C.ListenAddr.String())
|
proxyListener, err := net.Listen("tcp", config.C.Bind.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatal(err)
|
Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-132
@@ -7,7 +7,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -40,22 +39,16 @@ const (
|
|||||||
OptionTypeDebug OptionType = iota
|
OptionTypeDebug OptionType = iota
|
||||||
OptionTypeVerbose
|
OptionTypeVerbose
|
||||||
|
|
||||||
OptionTypeBindIP
|
OptionTypeBind
|
||||||
OptionTypeBindPort
|
|
||||||
OptionTypePublicIPv4
|
OptionTypePublicIPv4
|
||||||
OptionTypePublicIPv4Port
|
|
||||||
OptionTypePublicIPv6
|
OptionTypePublicIPv6
|
||||||
OptionTypePublicIPv6Port
|
|
||||||
OptionTypeStatsIP
|
|
||||||
OptionTypeStatsPort
|
|
||||||
|
|
||||||
OptionTypeStatsdIP
|
OptionTypeStatsBind
|
||||||
OptionTypeStatsdPort
|
OptionTypeStatsNamespace
|
||||||
|
OptionTypeStatsdAddress
|
||||||
OptionTypeStatsdNetwork
|
OptionTypeStatsdNetwork
|
||||||
OptionTypeStatsdPrefix
|
|
||||||
OptionTypeStatsdTagsFormat
|
OptionTypeStatsdTagsFormat
|
||||||
OptionTypeStatsdTags
|
OptionTypeStatsdTags
|
||||||
OptionTypePrometheusPrefix
|
|
||||||
|
|
||||||
OptionTypeWriteBufferSize
|
OptionTypeWriteBufferSize
|
||||||
OptionTypeReadBufferSize
|
OptionTypeReadBufferSize
|
||||||
@@ -67,93 +60,30 @@ const (
|
|||||||
OptionTypeAdtag
|
OptionTypeAdtag
|
||||||
)
|
)
|
||||||
|
|
||||||
type BufferSize struct {
|
|
||||||
Read int `json:"read"`
|
|
||||||
Write int `json:"write"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AntiReplay struct {
|
|
||||||
MaxSize int `json:"max_size"`
|
|
||||||
EvictionTime time.Duration `json:"duration"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stats struct {
|
|
||||||
Prefix string `json:"prefix"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type StatsdStats struct {
|
|
||||||
Stats
|
|
||||||
|
|
||||||
Addr Addr `json:"addr"`
|
|
||||||
Tags map[string]string `json:"tags"`
|
|
||||||
TagsFormat statsd.TagFormat `json:"format"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrometheusStats struct {
|
|
||||||
Stats
|
|
||||||
}
|
|
||||||
|
|
||||||
type Addr struct {
|
|
||||||
IP net.IP `json:"ip"`
|
|
||||||
Port int `json:"port"`
|
|
||||||
net string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Addr) Network() string {
|
|
||||||
if a.net == "" {
|
|
||||||
return "tcp"
|
|
||||||
}
|
|
||||||
return a.net
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Addr) String() string {
|
|
||||||
return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Addr) MarshalJSON() ([]byte, error) {
|
|
||||||
data := map[string]string{
|
|
||||||
"network": a.Network(),
|
|
||||||
"addr": a.String(),
|
|
||||||
}
|
|
||||||
return json.Marshal(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
BufferSize BufferSize `json:"buffer_size"`
|
Bind *net.TCPAddr `json:"bind"`
|
||||||
AntiReplay AntiReplay `json:"anti_replay"`
|
PublicIPv4 *net.TCPAddr `json:"public_ipv4"`
|
||||||
|
PublicIPv6 *net.TCPAddr `json:"public_ipv6"`
|
||||||
|
StatsBind *net.TCPAddr `json:"stats_bind"`
|
||||||
|
StatsdAddr *net.TCPAddr `json:"stats_addr"`
|
||||||
|
|
||||||
ListenAddr Addr `json:"listen_addr"`
|
StatsNamespace string `json:"stats_namespace"`
|
||||||
PublicIPv4Addr Addr `json:"public_ipv4_addr"`
|
StatsdNetwork string `json:"statsd_network"`
|
||||||
PublicIPv6Addr Addr `json:"public_ipv6_addr"`
|
StatsdTags map[string]string `json:"statsd_tags"`
|
||||||
StatsAddr Addr `json:"stats_addr"`
|
|
||||||
|
|
||||||
StatsdStats StatsdStats `json:"stats_statsd"`
|
WriteBuffer int `json:"write_buffer"`
|
||||||
PrometheusStats PrometheusStats `json:"stats_prometheus"`
|
ReadBuffer int `json:"read_buffer"`
|
||||||
|
|
||||||
Debug bool `json:"debug"`
|
AntiReplayMaxSize int `json:"anti_replay_max_size"`
|
||||||
Verbose bool `json:"verbose"`
|
AntiReplayEvictionTime time.Duration `json:"anti_replay_eviction_time"`
|
||||||
SecretMode SecretMode `json:"secret_mode"`
|
|
||||||
Secret []byte `json:"secret"`
|
|
||||||
AdTag []byte `json:"adtag"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Config) Printable() interface{} {
|
Debug bool `json:"debug"`
|
||||||
data, err := json.Marshal(c)
|
Verbose bool `json:"verbose"`
|
||||||
if err != nil {
|
StatsdTagsFormat statsd.TagFormat `json:"statsd_tags_format"`
|
||||||
panic(err)
|
SecretMode SecretMode `json:"secret_mode"`
|
||||||
}
|
|
||||||
|
|
||||||
rv := map[string]interface{}{}
|
Secret []byte `json:"secret"`
|
||||||
if err := json.Unmarshal(data, &rv); err != nil {
|
AdTag []byte `json:"adtag"`
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Config) String() string {
|
|
||||||
data, _ := json.Marshal(c)
|
|
||||||
return string(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Opt struct {
|
type Opt struct {
|
||||||
@@ -163,59 +93,53 @@ type Opt struct {
|
|||||||
|
|
||||||
var C = Config{}
|
var C = Config{}
|
||||||
|
|
||||||
func Init(options ...Opt) error { // nolint: gocyclo
|
func Init(options ...Opt) error { // nolint: gocyclo, funlen
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
switch opt.Option {
|
switch opt.Option {
|
||||||
case OptionTypeDebug:
|
case OptionTypeDebug:
|
||||||
C.Debug = opt.Value.(bool)
|
C.Debug = opt.Value.(bool)
|
||||||
case OptionTypeVerbose:
|
case OptionTypeVerbose:
|
||||||
C.Verbose = opt.Value.(bool)
|
C.Verbose = opt.Value.(bool)
|
||||||
case OptionTypeBindIP:
|
case OptionTypeBind:
|
||||||
C.ListenAddr.IP = opt.Value.(net.IP)
|
C.Bind = opt.Value.(*net.TCPAddr)
|
||||||
case OptionTypeBindPort:
|
|
||||||
C.ListenAddr.Port = int(opt.Value.(uint16))
|
|
||||||
case OptionTypePublicIPv4:
|
case OptionTypePublicIPv4:
|
||||||
C.PublicIPv4Addr.IP = opt.Value.(net.IP)
|
C.PublicIPv4 = opt.Value.(*net.TCPAddr)
|
||||||
case OptionTypePublicIPv4Port:
|
|
||||||
C.PublicIPv4Addr.Port = int(opt.Value.(uint16))
|
|
||||||
case OptionTypePublicIPv6:
|
case OptionTypePublicIPv6:
|
||||||
C.PublicIPv6Addr.IP = opt.Value.(net.IP)
|
C.PublicIPv6 = opt.Value.(*net.TCPAddr)
|
||||||
case OptionTypePublicIPv6Port:
|
case OptionTypeStatsBind:
|
||||||
C.PublicIPv6Addr.Port = int(opt.Value.(uint16))
|
C.StatsBind = opt.Value.(*net.TCPAddr)
|
||||||
case OptionTypeStatsIP:
|
case OptionTypeStatsNamespace:
|
||||||
C.StatsAddr.IP = opt.Value.(net.IP)
|
C.StatsNamespace = opt.Value.(string)
|
||||||
case OptionTypeStatsPort:
|
case OptionTypeStatsdAddress:
|
||||||
C.StatsAddr.Port = int(opt.Value.(uint16))
|
C.StatsdAddr = opt.Value.(*net.TCPAddr)
|
||||||
case OptionTypeStatsdIP:
|
|
||||||
C.StatsdStats.Addr.IP = opt.Value.(net.IP)
|
|
||||||
case OptionTypeStatsdPort:
|
|
||||||
C.StatsdStats.Addr.Port = int(opt.Value.(uint16))
|
|
||||||
case OptionTypeStatsdNetwork:
|
case OptionTypeStatsdNetwork:
|
||||||
C.StatsdStats.Addr.net = opt.Value.(string)
|
value := opt.Value.(string)
|
||||||
case OptionTypeStatsdPrefix:
|
switch value {
|
||||||
C.StatsdStats.Prefix = opt.Value.(string)
|
case "udp", "tcp":
|
||||||
|
C.StatsdNetwork = value
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown statsd network %v", value)
|
||||||
|
}
|
||||||
case OptionTypeStatsdTagsFormat:
|
case OptionTypeStatsdTagsFormat:
|
||||||
value := opt.Value.(string)
|
value := opt.Value.(string)
|
||||||
switch value {
|
switch value {
|
||||||
case "datadog":
|
case "datadog":
|
||||||
C.StatsdStats.TagsFormat = statsd.Datadog
|
C.StatsdTagsFormat = statsd.Datadog
|
||||||
case "influxdb":
|
case "influxdb":
|
||||||
C.StatsdStats.TagsFormat = statsd.InfluxDB
|
C.StatsdTagsFormat = statsd.InfluxDB
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Incorrect statsd tag %s", value)
|
return fmt.Errorf("Incorrect statsd tag %s", value)
|
||||||
}
|
}
|
||||||
case OptionTypeStatsdTags:
|
case OptionTypeStatsdTags:
|
||||||
C.StatsdStats.Tags = opt.Value.(map[string]string)
|
C.StatsdTags = opt.Value.(map[string]string)
|
||||||
case OptionTypePrometheusPrefix:
|
|
||||||
C.PrometheusStats.Prefix = opt.Value.(string)
|
|
||||||
case OptionTypeWriteBufferSize:
|
case OptionTypeWriteBufferSize:
|
||||||
C.BufferSize.Write = int(opt.Value.(uint32))
|
C.WriteBuffer = int(opt.Value.(uint32))
|
||||||
case OptionTypeReadBufferSize:
|
case OptionTypeReadBufferSize:
|
||||||
C.BufferSize.Read = int(opt.Value.(uint32))
|
C.ReadBuffer = int(opt.Value.(uint32))
|
||||||
case OptionTypeAntiReplayMaxSize:
|
case OptionTypeAntiReplayMaxSize:
|
||||||
C.AntiReplay.MaxSize = opt.Value.(int)
|
C.AntiReplayMaxSize = opt.Value.(int)
|
||||||
case OptionTypeAntiReplayEvictionTime:
|
case OptionTypeAntiReplayEvictionTime:
|
||||||
C.AntiReplay.EvictionTime = opt.Value.(time.Duration)
|
C.AntiReplayEvictionTime = opt.Value.(time.Duration)
|
||||||
case OptionTypeSecret:
|
case OptionTypeSecret:
|
||||||
C.Secret = opt.Value.([]byte)
|
C.Secret = opt.Value.([]byte)
|
||||||
case OptionTypeAdtag:
|
case OptionTypeAdtag:
|
||||||
@@ -239,29 +163,29 @@ func Init(options ...Opt) error { // nolint: gocyclo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitPublicAddress(ctx context.Context) error {
|
func InitPublicAddress(ctx context.Context) error {
|
||||||
if C.PublicIPv4Addr.Port == 0 {
|
if C.PublicIPv4.Port == 0 {
|
||||||
C.PublicIPv4Addr.Port = C.ListenAddr.Port
|
C.PublicIPv4.Port = C.Bind.Port
|
||||||
}
|
}
|
||||||
if C.PublicIPv6Addr.Port == 0 {
|
if C.PublicIPv6.Port == 0 {
|
||||||
C.PublicIPv6Addr.Port = C.ListenAddr.Port
|
C.PublicIPv6.Port = C.Bind.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
foundAddress := C.PublicIPv4Addr.IP != nil || C.PublicIPv6Addr.IP != nil
|
foundAddress := C.PublicIPv4.IP != nil || C.PublicIPv6.IP != nil
|
||||||
if C.PublicIPv4Addr.IP == nil {
|
if C.PublicIPv4.IP == nil {
|
||||||
ip, err := getGlobalIPv4(ctx)
|
ip, err := getGlobalIPv4(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Warnw("Cannot resolve public address", "error", err)
|
zap.S().Warnw("Cannot resolve public address", "error", err)
|
||||||
} else {
|
} else {
|
||||||
C.PublicIPv4Addr.IP = ip
|
C.PublicIPv4.IP = ip
|
||||||
foundAddress = true
|
foundAddress = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if C.PublicIPv6Addr.IP == nil {
|
if C.PublicIPv6.IP == nil {
|
||||||
ip, err := getGlobalIPv6(ctx)
|
ip, err := getGlobalIPv6(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Warnw("Cannot resolve public address", "error", err)
|
zap.S().Warnw("Cannot resolve public address", "error", err)
|
||||||
} else {
|
} else {
|
||||||
C.PublicIPv6Addr.IP = ip
|
C.PublicIPv6.IP = ip
|
||||||
foundAddress = true
|
foundAddress = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,3 +196,22 @@ func InitPublicAddress(ctx context.Context) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Printable() interface{} {
|
||||||
|
data, err := json.Marshal(C)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := map[string]interface{}{}
|
||||||
|
if err := json.Unmarshal(data, &rv); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rrv, err := json.Marshal(rv)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rrv
|
||||||
|
}
|
||||||
|
|||||||
+4
-3
@@ -2,6 +2,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,14 +28,14 @@ func GetURLs() (urls IPURLs) {
|
|||||||
secret = "dd" + hex.EncodeToString(C.Secret)
|
secret = "dd" + hex.EncodeToString(C.Secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
urls.IPv4 = makeURLs(&C.PublicIPv4Addr, secret)
|
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
|
||||||
urls.IPv6 = makeURLs(&C.PublicIPv6Addr, secret)
|
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
|
||||||
urls.BotSecret = secret
|
urls.BotSecret = secret
|
||||||
|
|
||||||
return urls
|
return urls
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeURLs(addr *Addr, secret string) (urls URLs) {
|
func makeURLs(addr fmt.Stringer, secret string) (urls URLs) {
|
||||||
values := url.Values{}
|
values := url.Values{}
|
||||||
values.Set("address", addr.String())
|
values.Set("address", addr.String())
|
||||||
values.Set("secret", secret)
|
values.Set("secret", secret)
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ func (c *connection) write(packet conntypes.Packet) error {
|
|||||||
func (c *connection) shutdown() {
|
func (c *connection) shutdown() {
|
||||||
c.shutdownOnce.Do(func() {
|
c.shutdownOnce.Do(func() {
|
||||||
close(c.done)
|
close(c.done)
|
||||||
c.hub.channelBrokenSockets <- c.id
|
c.hub.channelBrokenSockets <- c.id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package hub
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/conntypes"
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
|||||||
@@ -36,67 +36,42 @@ var (
|
|||||||
Short('v').
|
Short('v').
|
||||||
Envar("MTG_VERBOSE").
|
Envar("MTG_VERBOSE").
|
||||||
Bool()
|
Bool()
|
||||||
proxyBindIP = proxyCommand.Flag("bind-ip",
|
proxyBind = proxyCommand.Flag("bind",
|
||||||
"Which IP to bind to.").
|
"Host:Port to bind proxy to.").
|
||||||
Short('b').
|
Short('b').
|
||||||
Envar("MTG_IP").
|
Envar("MTG_BIND").
|
||||||
Default("127.0.0.1").
|
Default("0.0.0.0:3128").
|
||||||
IP()
|
TCP()
|
||||||
proxyBindPort = proxyCommand.Flag("bind-port",
|
|
||||||
"Which port to bind to.").
|
|
||||||
Short('p').
|
|
||||||
Envar("MTG_PORT").
|
|
||||||
Default("3128").
|
|
||||||
Uint16()
|
|
||||||
proxyPublicIPv4 = proxyCommand.Flag("public-ipv4",
|
proxyPublicIPv4 = proxyCommand.Flag("public-ipv4",
|
||||||
"Which IPv4 address is public.").
|
"Which IPv4 host:port to use.").
|
||||||
Short('4').
|
Short('4').
|
||||||
Envar("MTG_IPV4").
|
Envar("MTG_IPV4").
|
||||||
IP()
|
TCP()
|
||||||
proxyPublicIPv4Port = proxyCommand.Flag("public-ipv4-port",
|
|
||||||
"Which IPv4 port is public. Default is 'bind-port' value.").
|
|
||||||
Envar("MTG_IPV4_PORT").
|
|
||||||
Uint16()
|
|
||||||
proxyPublicIPv6 = proxyCommand.Flag("public-ipv6",
|
proxyPublicIPv6 = proxyCommand.Flag("public-ipv6",
|
||||||
"Which IPv6 address is public.").
|
"Which IPv6 host:port to use.").
|
||||||
Short('6').
|
Short('6').
|
||||||
Envar("MTG_IPV6").
|
Envar("MTG_IPV6").
|
||||||
IP()
|
TCP()
|
||||||
proxyPublicIPv6Port = proxyCommand.Flag("public-ipv6-port",
|
proxyStatsBind = proxyCommand.Flag("stats-bind",
|
||||||
"Which IPv6 port is public. Default is 'bind-port' value.").
|
"Which Host:Port to bind stats server to.").
|
||||||
Envar("MTG_IPV6_PORT").
|
|
||||||
Uint16()
|
|
||||||
proxyStatsIP = proxyCommand.Flag("stats-ip",
|
|
||||||
"Which IP bind stats server to.").
|
|
||||||
Short('t').
|
Short('t').
|
||||||
Envar("MTG_STATS_IP").
|
Envar("MTG_STATS_BIND").
|
||||||
Default("127.0.0.1").
|
Default("127.0.0.1:3129").
|
||||||
IP()
|
TCP()
|
||||||
proxyStatsPort = proxyCommand.Flag("stats-port",
|
proxyStatsNamespace = proxyCommand.Flag("prometheus-namespace",
|
||||||
"Which port bind stats to.").
|
"Which namespace to use for Prometheus.").
|
||||||
Short('q').
|
Envar("MTG_STATS_NAMESPACE").
|
||||||
Envar("MTG_STATS_PORT").
|
Default("mtg").
|
||||||
Default("3129").
|
String()
|
||||||
Uint16()
|
proxyStatsdAddress = proxyCommand.Flag("statsd-addr",
|
||||||
proxyStatsdIP = proxyCommand.Flag("statsd-ip",
|
"Host:port of statsd server").
|
||||||
"Which IP should we use for working with statsd.").
|
Envar("MTG_STATSD_ADDR").
|
||||||
Envar("MTG_STATSD_IP").
|
TCP()
|
||||||
IP()
|
|
||||||
proxyStatsdPort = proxyCommand.Flag("statsd-port",
|
|
||||||
"Which port should we use for working with statsd.").
|
|
||||||
Envar("MTG_STATSD_PORT").
|
|
||||||
Default("8125").
|
|
||||||
Uint16()
|
|
||||||
proxyStatsdNetwork = proxyCommand.Flag("statsd-network",
|
proxyStatsdNetwork = proxyCommand.Flag("statsd-network",
|
||||||
"Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
|
"Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
|
||||||
Envar("MTG_STATSD_NETWORK").
|
Envar("MTG_STATSD_NETWORK").
|
||||||
Default("udp").
|
Default("udp").
|
||||||
Enum("udp", "tcp")
|
Enum("udp", "tcp")
|
||||||
proxyStatsdPrefix = proxyCommand.Flag("statsd-prefix",
|
|
||||||
"Which bucket prefix should we use for sending stats to statsd.").
|
|
||||||
Envar("MTG_STATSD_PREFIX").
|
|
||||||
Default("mtg").
|
|
||||||
String()
|
|
||||||
proxyStatsdTagsFormat = proxyCommand.Flag("statsd-tags-format",
|
proxyStatsdTagsFormat = proxyCommand.Flag("statsd-tags-format",
|
||||||
"Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
|
"Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
|
||||||
Envar("MTG_STATSD_TAGS_FORMAT").
|
Envar("MTG_STATSD_TAGS_FORMAT").
|
||||||
@@ -106,23 +81,18 @@ var (
|
|||||||
"Tags to use for working with statsd (specified as 'key=value').").
|
"Tags to use for working with statsd (specified as 'key=value').").
|
||||||
Envar("MTG_STATSD_TAGS").
|
Envar("MTG_STATSD_TAGS").
|
||||||
StringMap()
|
StringMap()
|
||||||
proxyPrometheusPrefix = proxyCommand.Flag("prometheus-prefix",
|
|
||||||
"Which namespace to use to send stats to Prometheus.").
|
|
||||||
Envar("MTG_PROMETHEUS_PREFIX").
|
|
||||||
Default("mtg").
|
|
||||||
String()
|
|
||||||
proxyWriteBufferSize = proxyCommand.Flag("write-buffer",
|
proxyWriteBufferSize = proxyCommand.Flag("write-buffer",
|
||||||
"Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
|
"Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
|
||||||
Short('w').
|
Short('w').
|
||||||
Envar("MTG_BUFFER_WRITE").
|
Envar("MTG_BUFFER_WRITE").
|
||||||
Default("65536").
|
Default("65536KB").
|
||||||
Uint32()
|
Bytes()
|
||||||
proxyReadBufferSize = proxyCommand.Flag("read-buffer",
|
proxyReadBufferSize = proxyCommand.Flag("read-buffer",
|
||||||
"Read buffer size in bytes. You can think about it as a buffer from Telegram to client.").
|
"Read buffer size in bytes. You can think about it as a buffer from Telegram to client.").
|
||||||
Short('r').
|
Short('r').
|
||||||
Envar("MTG_BUFFER_READ").
|
Envar("MTG_BUFFER_READ").
|
||||||
Default("131072").
|
Default("131072KB").
|
||||||
Uint32()
|
Bytes()
|
||||||
proxyAntiReplayMaxSize = proxyCommand.Flag("anti-replay-max-size",
|
proxyAntiReplayMaxSize = proxyCommand.Flag("anti-replay-max-size",
|
||||||
"Max size of antireplay cache in megabytes.").
|
"Max size of antireplay cache in megabytes.").
|
||||||
Envar("MTG_ANTIREPLAY_MAXSIZE").
|
Envar("MTG_ANTIREPLAY_MAXSIZE").
|
||||||
@@ -154,21 +124,15 @@ func main() {
|
|||||||
err := config.Init(
|
err := config.Init(
|
||||||
config.Opt{Option: config.OptionTypeDebug, Value: *proxyDebug},
|
config.Opt{Option: config.OptionTypeDebug, Value: *proxyDebug},
|
||||||
config.Opt{Option: config.OptionTypeVerbose, Value: *proxyVerbose},
|
config.Opt{Option: config.OptionTypeVerbose, Value: *proxyVerbose},
|
||||||
config.Opt{Option: config.OptionTypeBindIP, Value: *proxyBindIP},
|
config.Opt{Option: config.OptionTypeBind, Value: *proxyBind},
|
||||||
config.Opt{Option: config.OptionTypeBindPort, Value: *proxyBindPort},
|
|
||||||
config.Opt{Option: config.OptionTypePublicIPv4, Value: *proxyPublicIPv4},
|
config.Opt{Option: config.OptionTypePublicIPv4, Value: *proxyPublicIPv4},
|
||||||
config.Opt{Option: config.OptionTypePublicIPv4Port, Value: *proxyPublicIPv4Port},
|
|
||||||
config.Opt{Option: config.OptionTypePublicIPv6, Value: *proxyPublicIPv6},
|
config.Opt{Option: config.OptionTypePublicIPv6, Value: *proxyPublicIPv6},
|
||||||
config.Opt{Option: config.OptionTypePublicIPv6Port, Value: *proxyPublicIPv6Port},
|
config.Opt{Option: config.OptionTypeStatsBind, Value: *proxyStatsBind},
|
||||||
config.Opt{Option: config.OptionTypeStatsIP, Value: *proxyStatsIP},
|
config.Opt{Option: config.OptionTypeStatsNamespace, Value: *proxyStatsNamespace},
|
||||||
config.Opt{Option: config.OptionTypeStatsPort, Value: *proxyStatsPort},
|
config.Opt{Option: config.OptionTypeStatsdAddress, Value: *proxyStatsdAddress},
|
||||||
config.Opt{Option: config.OptionTypeStatsdIP, Value: *proxyStatsdIP},
|
|
||||||
config.Opt{Option: config.OptionTypeStatsdPort, Value: *proxyStatsdPort},
|
|
||||||
config.Opt{Option: config.OptionTypeStatsdNetwork, Value: *proxyStatsdNetwork},
|
config.Opt{Option: config.OptionTypeStatsdNetwork, Value: *proxyStatsdNetwork},
|
||||||
config.Opt{Option: config.OptionTypeStatsdPrefix, Value: *proxyStatsdPrefix},
|
|
||||||
config.Opt{Option: config.OptionTypeStatsdTagsFormat, Value: *proxyStatsdTagsFormat},
|
config.Opt{Option: config.OptionTypeStatsdTagsFormat, Value: *proxyStatsdTagsFormat},
|
||||||
config.Opt{Option: config.OptionTypeStatsdTags, Value: *proxyStatsdTags},
|
config.Opt{Option: config.OptionTypeStatsdTags, Value: *proxyStatsdTags},
|
||||||
config.Opt{Option: config.OptionTypePrometheusPrefix, Value: *proxyPrometheusPrefix},
|
|
||||||
config.Opt{Option: config.OptionTypeWriteBufferSize, Value: *proxyWriteBufferSize},
|
config.Opt{Option: config.OptionTypeWriteBufferSize, Value: *proxyWriteBufferSize},
|
||||||
config.Opt{Option: config.OptionTypeReadBufferSize, Value: *proxyReadBufferSize},
|
config.Opt{Option: config.OptionTypeReadBufferSize, Value: *proxyReadBufferSize},
|
||||||
config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *proxyAntiReplayMaxSize},
|
config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *proxyAntiReplayMaxSize},
|
||||||
|
|||||||
+3
-4
@@ -47,7 +47,7 @@ func (p *Proxy) accept(conn net.Conn) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
stats.S.Crash()
|
stats.Stats.Crash()
|
||||||
p.Logger.Errorw("Crash of accept handler", "error", err)
|
p.Logger.Errorw("Crash of accept handler", "error", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -66,7 +66,6 @@ func (p *Proxy) accept(conn net.Conn) {
|
|||||||
clientConn := wrappers.NewClientConn(conn, connID)
|
clientConn := wrappers.NewClientConn(conn, connID)
|
||||||
clientConn = wrappers.NewCtx(ctx, cancel, clientConn)
|
clientConn = wrappers.NewCtx(ctx, cancel, clientConn)
|
||||||
clientConn = wrappers.NewTimeout(clientConn)
|
clientConn = wrappers.NewTimeout(clientConn)
|
||||||
clientConn = wrappers.NewTraffic(clientConn)
|
|
||||||
defer clientConn.Close()
|
defer clientConn.Close()
|
||||||
|
|
||||||
clientProtocol := p.ClientProtocolMaker()
|
clientProtocol := p.ClientProtocolMaker()
|
||||||
@@ -76,8 +75,8 @@ func (p *Proxy) accept(conn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.S.ClientConnected(clientProtocol.ConnectionType(), clientConn.RemoteAddr())
|
stats.Stats.ClientConnected(clientProtocol.ConnectionType(), clientConn.RemoteAddr())
|
||||||
defer stats.S.ClientDisconnected(clientProtocol.ConnectionType(), clientConn.RemoteAddr())
|
defer stats.Stats.ClientDisconnected(clientProtocol.ConnectionType(), clientConn.RemoteAddr())
|
||||||
logger.Infow("Client connected", "addr", conn.RemoteAddr())
|
logger.Infow("Client connected", "addr", conn.RemoteAddr())
|
||||||
|
|
||||||
req := &protocol.TelegramRequest{
|
req := &protocol.TelegramRequest{
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IngressTrafficInterface interface {
|
||||||
|
IngressTraffic(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type EgressTrafficInterface interface {
|
||||||
|
EgressTraffic(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientConnectedInterface interface {
|
||||||
|
ClientConnected(conntypes.ConnectionType, *net.TCPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientDisconnectedInterface interface {
|
||||||
|
ClientDisconnected(conntypes.ConnectionType, *net.TCPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TelegramConnectedInterface interface {
|
||||||
|
TelegramConnected(conntypes.DC, *net.TCPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TelegramDisconnectedInterface interface {
|
||||||
|
TelegramDisconnected(conntypes.DC, *net.TCPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CrashInterface interface {
|
||||||
|
Crash()
|
||||||
|
}
|
||||||
|
|
||||||
|
type AntiReplayDetectedInterface interface {
|
||||||
|
AntiReplayDetected()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
IngressTrafficInterface
|
||||||
|
EgressTrafficInterface
|
||||||
|
ClientConnectedInterface
|
||||||
|
ClientDisconnectedInterface
|
||||||
|
TelegramConnectedInterface
|
||||||
|
TelegramDisconnectedInterface
|
||||||
|
CrashInterface
|
||||||
|
AntiReplayDetectedInterface
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package stats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type multiStats []Interface
|
||||||
|
|
||||||
|
func (m multiStats) IngressTraffic(traffic int) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].IngressTraffic(traffic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) EgressTraffic(traffic int) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].EgressTraffic(traffic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) ClientConnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].ClientConnected(connectionType, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) ClientDisconnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].ClientDisconnected(connectionType, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) TelegramConnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].TelegramConnected(dc, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) TelegramDisconnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].TelegramDisconnected(dc, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) Crash() {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].Crash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiStats) AntiReplayDetected() {
|
||||||
|
for i := range m {
|
||||||
|
go m[i].AntiReplayDetected()
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-54
@@ -7,69 +7,20 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/config"
|
"github.com/9seconds/mtg/config"
|
||||||
"github.com/9seconds/mtg/conntypes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Stats interface {
|
var Stats Interface
|
||||||
IngressTraffic(int)
|
|
||||||
EgressTraffic(int)
|
|
||||||
ClientConnected(conntypes.ConnectionType, *net.TCPAddr)
|
|
||||||
ClientDisconnected(conntypes.ConnectionType, *net.TCPAddr)
|
|
||||||
Crash()
|
|
||||||
AntiReplayDetected()
|
|
||||||
}
|
|
||||||
|
|
||||||
type multiStats []Stats
|
|
||||||
|
|
||||||
func (m multiStats) IngressTraffic(traffic int) {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].IngressTraffic(traffic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m multiStats) EgressTraffic(traffic int) {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].EgressTraffic(traffic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m multiStats) ClientConnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].ClientConnected(connectionType, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m multiStats) ClientDisconnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].ClientDisconnected(connectionType, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m multiStats) Crash() {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].Crash()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m multiStats) AntiReplayDetected() {
|
|
||||||
for i := range m {
|
|
||||||
go m[i].AntiReplayDetected()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var S Stats
|
|
||||||
|
|
||||||
func Init(ctx context.Context) error {
|
func Init(ctx context.Context) error {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
instanceJSON := newStatsJSON(mux)
|
|
||||||
instancePrometheus, err := newStatsPrometheus(mux)
|
instancePrometheus, err := newStatsPrometheus(mux)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot initialize prometheus: %w", err)
|
return fmt.Errorf("cannot initialize prometheus: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stats := []Stats{instanceJSON, instancePrometheus}
|
stats := []Interface{instancePrometheus}
|
||||||
if config.C.StatsdStats.Addr.IP != nil {
|
if config.C.StatsdAddr != nil {
|
||||||
instanceStatsd, err := newStatsStatsd()
|
instanceStatsd, err := newStatsStatsd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot inialize statsd: %w", err)
|
return fmt.Errorf("cannot inialize statsd: %w", err)
|
||||||
@@ -77,7 +28,7 @@ func Init(ctx context.Context) error {
|
|||||||
stats = append(stats, instanceStatsd)
|
stats = append(stats, instanceStatsd)
|
||||||
}
|
}
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", config.C.StatsAddr.String())
|
listener, err := net.Listen("tcp", config.C.StatsBind.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot initialize stats server: %w", err)
|
return fmt.Errorf("cannot initialize stats server: %w", err)
|
||||||
}
|
}
|
||||||
@@ -91,7 +42,7 @@ func Init(ctx context.Context) error {
|
|||||||
srv.Shutdown(context.Background()) // nolint: errcheck
|
srv.Shutdown(context.Background()) // nolint: errcheck
|
||||||
}()
|
}()
|
||||||
|
|
||||||
S = multiStats(stats)
|
Stats = multiStats(stats)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
package stats
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
|
|
||||||
"github.com/9seconds/mtg/conntypes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type statsJSON struct {
|
|
||||||
Connections statsJSONConnections `json:"connections"`
|
|
||||||
Traffic statsJSONTraffic `json:"traffic"`
|
|
||||||
Uptime statsJSONUptime `json:"uptime"`
|
|
||||||
Crashes uint32 `json:"crashes"`
|
|
||||||
AntiReplays uint32 `json:"anti_replay_detected"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type statsBaseJSONConnections struct {
|
|
||||||
All statsJSONConnectionType `json:"all"`
|
|
||||||
Abridged statsJSONConnectionType `json:"abridged"`
|
|
||||||
Intermediate statsJSONConnectionType `json:"intermediate"`
|
|
||||||
Secured statsJSONConnectionType `json:"secured"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type statsJSONConnections struct {
|
|
||||||
statsBaseJSONConnections
|
|
||||||
}
|
|
||||||
|
|
||||||
type statsJSONConnectionType struct {
|
|
||||||
IPv4 uint32 `json:"ipv4"`
|
|
||||||
IPv6 uint32 `json:"ipv6"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c statsJSONConnections) MarshalJSON() ([]byte, error) {
|
|
||||||
c.All.IPv4 = c.Abridged.IPv4 + c.Intermediate.IPv4 + c.Secured.IPv4
|
|
||||||
c.All.IPv6 = c.Abridged.IPv6 + c.Intermediate.IPv6 + c.Secured.IPv6
|
|
||||||
|
|
||||||
return json.Marshal(c.statsBaseJSONConnections)
|
|
||||||
}
|
|
||||||
|
|
||||||
type statsJSONTraffic struct {
|
|
||||||
Ingress uint64 `json:"ingress"`
|
|
||||||
Egress uint64 `json:"egress"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type statsJSONUptime time.Time
|
|
||||||
|
|
||||||
func (s statsJSONUptime) MarshalJSON() ([]byte, error) {
|
|
||||||
seconds := strconv.Itoa(int(time.Since(time.Time(s)).Seconds()))
|
|
||||||
return []byte(seconds), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) IngressTraffic(traffic int) {
|
|
||||||
atomic.AddUint64(&s.Traffic.Ingress, uint64(traffic))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) EgressTraffic(traffic int) {
|
|
||||||
atomic.AddUint64(&s.Traffic.Egress, uint64(traffic))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) ClientConnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
|
||||||
s.changeConnections(connectionType, addr, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) ClientDisconnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
|
|
||||||
s.changeConnections(connectionType, addr, ^uint32(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, value uint32) {
|
|
||||||
var connections *statsJSONConnectionType
|
|
||||||
|
|
||||||
switch connectionType {
|
|
||||||
case conntypes.ConnectionTypeAbridged:
|
|
||||||
connections = &s.Connections.Abridged
|
|
||||||
case conntypes.ConnectionTypeSecure:
|
|
||||||
connections = &s.Connections.Secured
|
|
||||||
default:
|
|
||||||
connections = &s.Connections.Intermediate
|
|
||||||
}
|
|
||||||
|
|
||||||
if addr.IP.To4() != nil {
|
|
||||||
atomic.AddUint32(&connections.IPv4, value)
|
|
||||||
} else {
|
|
||||||
atomic.AddUint32(&connections.IPv6, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) Crash() {
|
|
||||||
atomic.AddUint32(&s.Crashes, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statsJSON) AntiReplayDetected() {
|
|
||||||
atomic.AddUint32(&s.AntiReplays, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStatsJSON(mux *http.ServeMux) Stats {
|
|
||||||
instance := &statsJSON{
|
|
||||||
Uptime: statsJSONUptime(time.Now()),
|
|
||||||
}
|
|
||||||
logger := zap.S().Named("stats")
|
|
||||||
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
first, err := json.Marshal(instance)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorw("Cannot encode json", "error", err)
|
|
||||||
http.Error(w, "Internal server error", http.StatusServiceUnavailable)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
interim := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal(first, &interim); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
|
||||||
encoder.SetEscapeHTML(false)
|
|
||||||
encoder.SetIndent("", " ")
|
|
||||||
if err := encoder.Encode(interim); err != nil {
|
|
||||||
logger.Errorw("Cannot encode json", "error", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return instance
|
|
||||||
}
|
|
||||||
+46
-17
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
@@ -13,10 +14,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type statsPrometheus struct {
|
type statsPrometheus struct {
|
||||||
connections *prometheus.GaugeVec
|
connections *prometheus.GaugeVec
|
||||||
traffic *prometheus.GaugeVec
|
telegramConnections *prometheus.GaugeVec
|
||||||
crashes prometheus.Gauge
|
traffic *prometheus.GaugeVec
|
||||||
antiReplays prometheus.Gauge
|
crashes prometheus.Gauge
|
||||||
|
antiReplays prometheus.Counter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsPrometheus) IngressTraffic(traffic int) {
|
func (s *statsPrometheus) IngressTraffic(traffic int) {
|
||||||
@@ -38,18 +40,39 @@ func (s *statsPrometheus) ClientDisconnected(connectionType conntypes.Connection
|
|||||||
func (s *statsPrometheus) changeConnections(connectionType conntypes.ConnectionType,
|
func (s *statsPrometheus) changeConnections(connectionType conntypes.ConnectionType,
|
||||||
addr *net.TCPAddr,
|
addr *net.TCPAddr,
|
||||||
increment float64) {
|
increment float64) {
|
||||||
var labels [2]string
|
labels := [...]string{
|
||||||
|
"intermediate",
|
||||||
|
"ipv4",
|
||||||
|
}
|
||||||
|
|
||||||
switch connectionType {
|
switch connectionType {
|
||||||
case conntypes.ConnectionTypeAbridged:
|
case conntypes.ConnectionTypeAbridged:
|
||||||
labels[0] = "abridged"
|
labels[0] = "abridged"
|
||||||
case conntypes.ConnectionTypeSecure:
|
case conntypes.ConnectionTypeSecure:
|
||||||
labels[0] = "secured"
|
labels[0] = "secured"
|
||||||
default:
|
|
||||||
labels[0] = "intermediate"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
labels[1] = "ipv4"
|
if addr.IP.To4() == nil {
|
||||||
|
labels[1] = "ipv6" // nolint: goconst
|
||||||
|
}
|
||||||
|
|
||||||
|
s.connections.WithLabelValues(labels[:]...).Add(increment)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsPrometheus) TelegramConnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
s.changeTelegramConnections(dc, addr, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsPrometheus) TelegramDisconnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
s.changeTelegramConnections(dc, addr, -1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsPrometheus) changeTelegramConnections(dc conntypes.DC, addr *net.TCPAddr, increment float64) {
|
||||||
|
labels := [...]string{
|
||||||
|
strconv.Itoa(int(dc)),
|
||||||
|
"ipv4",
|
||||||
|
}
|
||||||
|
|
||||||
if addr.IP.To4() == nil {
|
if addr.IP.To4() == nil {
|
||||||
labels[1] = "ipv6"
|
labels[1] = "ipv6"
|
||||||
}
|
}
|
||||||
@@ -65,26 +88,32 @@ func (s *statsPrometheus) AntiReplayDetected() {
|
|||||||
s.antiReplays.Inc()
|
s.antiReplays.Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStatsPrometheus(mux *http.ServeMux) (Stats, error) {
|
func newStatsPrometheus(mux *http.ServeMux) (Interface, error) {
|
||||||
registry := prometheus.NewRegistry()
|
registry := prometheus.NewPedanticRegistry()
|
||||||
|
|
||||||
instance := &statsPrometheus{
|
instance := &statsPrometheus{
|
||||||
connections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
connections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Namespace: config.C.PrometheusStats.Prefix,
|
Namespace: config.C.StatsNamespace,
|
||||||
Name: "connections",
|
Name: "connections",
|
||||||
Help: "Current number of connections to the proxy.",
|
Help: "Current number of client connections to the proxy.",
|
||||||
}, []string{"type", "protocol"}),
|
}, []string{"type", "protocol"}),
|
||||||
|
telegramConnections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Namespace: config.C.StatsNamespace,
|
||||||
|
Name: "telegram_connections",
|
||||||
|
Help: "Current number of telegram connections established by this proxy.",
|
||||||
|
}, []string{"dc", "protocol"}),
|
||||||
traffic: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
traffic: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Namespace: config.C.PrometheusStats.Prefix,
|
Namespace: config.C.StatsNamespace,
|
||||||
Name: "traffic",
|
Name: "traffic",
|
||||||
Help: "Traffic passed through the proxy in bytes.",
|
Help: "Traffic passed through the proxy in bytes.",
|
||||||
}, []string{"direction"}),
|
}, []string{"direction"}),
|
||||||
crashes: prometheus.NewGauge(prometheus.GaugeOpts{
|
crashes: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: config.C.PrometheusStats.Prefix,
|
Namespace: config.C.StatsNamespace,
|
||||||
Name: "crashes",
|
Name: "crashes",
|
||||||
Help: "How many crashes happened.",
|
Help: "How many crashes happened.",
|
||||||
}),
|
}),
|
||||||
antiReplays: prometheus.NewGauge(prometheus.GaugeOpts{
|
antiReplays: prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Namespace: config.C.PrometheusStats.Prefix,
|
Namespace: config.C.StatsNamespace,
|
||||||
Name: "anti_replays",
|
Name: "anti_replays",
|
||||||
Help: "How many anti replay attacks were prevented.",
|
Help: "How many anti replay attacks were prevented.",
|
||||||
}),
|
}),
|
||||||
@@ -104,7 +133,7 @@ func newStatsPrometheus(mux *http.ServeMux) (Stats, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
|
handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
|
||||||
mux.Handle("/prometheus", handler)
|
mux.Handle("/", handler)
|
||||||
|
|
||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-13
@@ -3,6 +3,7 @@ package stats
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/alexcesaro/statsd.v2"
|
"gopkg.in/alexcesaro/statsd.v2"
|
||||||
@@ -32,19 +33,41 @@ func (s *statsStatsd) ClientDisconnected(connectionType conntypes.ConnectionType
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, value int) {
|
func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, value int) {
|
||||||
var labels [3]string
|
labels := [...]string{
|
||||||
|
"connections",
|
||||||
|
"intermediate",
|
||||||
|
"ipv4",
|
||||||
|
}
|
||||||
|
|
||||||
labels[0] = "connections"
|
|
||||||
switch connectionType {
|
switch connectionType {
|
||||||
case conntypes.ConnectionTypeAbridged:
|
case conntypes.ConnectionTypeAbridged:
|
||||||
labels[1] = "abridged"
|
labels[1] = "abridged"
|
||||||
case conntypes.ConnectionTypeSecure:
|
case conntypes.ConnectionTypeSecure:
|
||||||
labels[1] = "secured"
|
labels[1] = "secured"
|
||||||
default:
|
|
||||||
labels[1] = "intermediate"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
labels[2] = "ipv4"
|
if addr.IP.To4() == nil {
|
||||||
|
labels[2] = "ipv6"
|
||||||
|
}
|
||||||
|
|
||||||
|
s.client.Count(strings.Join(labels[:], "."), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsStatsd) TelegramConnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
s.changeTelegramConnections(dc, addr, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsStatsd) TelegramDisconnected(dc conntypes.DC, addr *net.TCPAddr) {
|
||||||
|
s.changeTelegramConnections(dc, addr, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statsStatsd) changeTelegramConnections(dc conntypes.DC, addr *net.TCPAddr, value int) {
|
||||||
|
labels := [...]string{
|
||||||
|
"telegram",
|
||||||
|
strconv.Itoa(int(dc)),
|
||||||
|
"ipv4",
|
||||||
|
}
|
||||||
|
|
||||||
if addr.IP.To4() == nil {
|
if addr.IP.To4() == nil {
|
||||||
labels[2] = "ipv6"
|
labels[2] = "ipv6"
|
||||||
}
|
}
|
||||||
@@ -60,17 +83,17 @@ func (s *statsStatsd) AntiReplayDetected() {
|
|||||||
s.client.Increment("anti_replays")
|
s.client.Increment("anti_replays")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStatsStatsd() (Stats, error) {
|
func newStatsStatsd() (Interface, error) {
|
||||||
options := []statsd.Option{
|
options := []statsd.Option{
|
||||||
statsd.Prefix(config.C.StatsdStats.Prefix),
|
statsd.Prefix(config.C.StatsNamespace),
|
||||||
statsd.Network(config.C.StatsdStats.Addr.Network()),
|
statsd.Network(config.C.StatsdNetwork),
|
||||||
statsd.Address(config.C.StatsdStats.Addr.String()),
|
statsd.Address(config.C.StatsBind.String()),
|
||||||
statsd.TagsFormat(config.C.StatsdStats.TagsFormat),
|
statsd.TagsFormat(config.C.StatsdTagsFormat),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.C.StatsdStats.Tags) > 0 {
|
if len(config.C.StatsdTags) > 0 {
|
||||||
tags := make([]string, len(config.C.StatsdStats.Tags)*2)
|
tags := make([]string, len(config.C.StatsdTags)*2)
|
||||||
for k, v := range config.C.StatsdStats.Tags {
|
for k, v := range config.C.StatsdTags {
|
||||||
tags = append(tags, k, v)
|
tags = append(tags, k, v)
|
||||||
}
|
}
|
||||||
options = append(options, statsd.Tags(tags...))
|
options = append(options, statsd.Tags(tags...))
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ func (b *baseTelegram) dial(dc conntypes.DC,
|
|||||||
return nil, fmt.Errorf("cannot initialize tcp socket: %w", err)
|
return nil, fmt.Errorf("cannot initialize tcp socket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrappers.NewTelegramConn(conn), nil
|
return wrappers.NewTelegramConn(dc, conn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
|
func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
|
||||||
|
|||||||
+2
-2
@@ -13,10 +13,10 @@ func InitTCP(conn net.Conn) error {
|
|||||||
if err := tcpConn.SetNoDelay(true); err != nil {
|
if err := tcpConn.SetNoDelay(true); err != nil {
|
||||||
return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
|
return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
|
||||||
}
|
}
|
||||||
if err := tcpConn.SetReadBuffer(config.C.BufferSize.Read); err != nil {
|
if err := tcpConn.SetReadBuffer(config.C.ReadBuffer); err != nil {
|
||||||
return fmt.Errorf("cannot set read buffer size: %w", err)
|
return fmt.Errorf("cannot set read buffer size: %w", err)
|
||||||
}
|
}
|
||||||
if err := tcpConn.SetWriteBuffer(config.C.BufferSize.Write); err != nil {
|
if err := tcpConn.SetWriteBuffer(config.C.WriteBuffer); err != nil {
|
||||||
return fmt.Errorf("cannot set write buffer size: %w", err)
|
return fmt.Errorf("cannot set write buffer size: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package wrappers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClientConn(parent net.Conn, connID conntypes.ConnID) conntypes.StreamReadWriteCloser {
|
||||||
|
conn := newConn(parent, connID, connPurposeClient)
|
||||||
|
conn = NewTrafficStats(conn)
|
||||||
|
|
||||||
|
return conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramConn(dc conntypes.DC, parent net.Conn) conntypes.StreamReadWriteCloser {
|
||||||
|
conn := newConn(parent, conntypes.ConnID{}, connPurposeTelegram)
|
||||||
|
conn = NewTelegramStats(dc, conn)
|
||||||
|
|
||||||
|
return conn
|
||||||
|
}
|
||||||
+4
-13
@@ -91,11 +91,11 @@ func newConn(parent net.Conn,
|
|||||||
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
||||||
|
|
||||||
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil {
|
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil {
|
||||||
if config.C.PublicIPv4Addr.IP != nil {
|
if config.C.PublicIPv4.IP != nil {
|
||||||
localAddr.IP = config.C.PublicIPv4Addr.IP
|
localAddr.IP = config.C.PublicIPv4.IP
|
||||||
}
|
}
|
||||||
} else if config.C.PublicIPv6Addr.IP != nil {
|
} else if config.C.PublicIPv6.IP != nil {
|
||||||
localAddr.IP = config.C.PublicIPv6Addr.IP
|
localAddr.IP = config.C.PublicIPv6.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := zap.S().With(
|
logger := zap.S().With(
|
||||||
@@ -115,12 +115,3 @@ func newConn(parent net.Conn,
|
|||||||
localAddr: &localAddr,
|
localAddr: &localAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientConn(parent net.Conn,
|
|
||||||
connID conntypes.ConnID) conntypes.StreamReadWriteCloser {
|
|
||||||
return newConn(parent, connID, connPurposeClient)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTelegramConn(parent net.Conn) conntypes.StreamReadWriteCloser {
|
|
||||||
return newConn(parent, conntypes.ConnID{}, connPurposeTelegram)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
package wrappers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
|
|
||||||
"github.com/9seconds/mtg/conntypes"
|
|
||||||
"github.com/9seconds/mtg/stats"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wrapperStats struct {
|
|
||||||
parent conntypes.StreamReadWriteCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) Write(p []byte) (int, error) {
|
|
||||||
n, err := w.parent.Write(p)
|
|
||||||
stats.S.EgressTraffic(n)
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
|
||||||
n, err := w.parent.WriteTimeout(p, timeout)
|
|
||||||
stats.S.EgressTraffic(n)
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) Read(p []byte) (int, error) {
|
|
||||||
n, err := w.parent.Read(p)
|
|
||||||
stats.S.IngressTraffic(n)
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
|
||||||
n, err := w.parent.ReadTimeout(p, timeout)
|
|
||||||
stats.S.IngressTraffic(n)
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) Conn() net.Conn {
|
|
||||||
return w.parent.Conn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) Logger() *zap.SugaredLogger {
|
|
||||||
return w.parent.Logger().Named("traffic")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) LocalAddr() *net.TCPAddr {
|
|
||||||
return w.parent.LocalAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) RemoteAddr() *net.TCPAddr {
|
|
||||||
return w.parent.RemoteAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperStats) Close() error {
|
|
||||||
return w.parent.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTraffic(parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
|
||||||
return &wrapperStats{parent}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package wrappers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
"github.com/9seconds/mtg/stats"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrapperTelegramStats struct {
|
||||||
|
parent conntypes.StreamReadWriteCloser
|
||||||
|
dc conntypes.DC
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) Write(p []byte) (int, error) {
|
||||||
|
return w.parent.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||||
|
return w.parent.WriteTimeout(p, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) Read(p []byte) (int, error) {
|
||||||
|
return w.parent.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||||
|
return w.parent.ReadTimeout(p, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) Conn() net.Conn {
|
||||||
|
return w.parent.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) Logger() *zap.SugaredLogger {
|
||||||
|
return w.parent.Logger().Named("stats-telegram")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) LocalAddr() *net.TCPAddr {
|
||||||
|
return w.parent.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) RemoteAddr() *net.TCPAddr {
|
||||||
|
return w.parent.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTelegramStats) Close() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
w.once.Do(func() {
|
||||||
|
err = w.parent.Close()
|
||||||
|
stats.Stats.TelegramDisconnected(w.dc, w.RemoteAddr())
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramStats(dc conntypes.DC, parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
||||||
|
conn := &wrapperTelegramStats{
|
||||||
|
parent: parent,
|
||||||
|
dc: dc,
|
||||||
|
}
|
||||||
|
stats.Stats.TelegramConnected(dc, parent.RemoteAddr())
|
||||||
|
|
||||||
|
return conn
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package wrappers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
"github.com/9seconds/mtg/stats"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrapperTrafficStats struct {
|
||||||
|
parent conntypes.StreamReadWriteCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) Write(p []byte) (int, error) {
|
||||||
|
n, err := w.parent.Write(p)
|
||||||
|
stats.Stats.EgressTraffic(n)
|
||||||
|
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||||
|
n, err := w.parent.WriteTimeout(p, timeout)
|
||||||
|
stats.Stats.EgressTraffic(n)
|
||||||
|
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) Read(p []byte) (int, error) {
|
||||||
|
n, err := w.parent.Read(p)
|
||||||
|
stats.Stats.IngressTraffic(n)
|
||||||
|
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||||
|
n, err := w.parent.ReadTimeout(p, timeout)
|
||||||
|
stats.Stats.IngressTraffic(n)
|
||||||
|
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) Conn() net.Conn {
|
||||||
|
return w.parent.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) Logger() *zap.SugaredLogger {
|
||||||
|
return w.parent.Logger().Named("stats-traffic")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) LocalAddr() *net.TCPAddr {
|
||||||
|
return w.parent.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) RemoteAddr() *net.TCPAddr {
|
||||||
|
return w.parent.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapperTrafficStats) Close() error {
|
||||||
|
return w.parent.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTrafficStats(parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
||||||
|
return &wrapperTrafficStats{parent}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user