Sfoglia il codice sorgente

Fix for statsd incorrect types

tags/1.0^2
9seconds 6 anni fa
parent
commit
dfa53af567
8 ha cambiato i file con 162 aggiunte e 116 eliminazioni
  1. 0
    1
      README.md
  2. 12
    22
      config/config.go
  3. 4
    3
      go.mod
  4. 11
    6
      go.sum
  5. 0
    6
      main.go
  6. 2
    13
      stats/stats.go
  7. 9
    24
      stats/stats_prometheus.go
  8. 124
    41
      stats/stats_statsd.go

+ 0
- 1
README.md Vedi File

@@ -181,7 +181,6 @@ supported environment variables:
181 181
 | `MTG_STATS_NAMESPACE`         | `--stats-namespace`          | `mtg`                             | Which namespace should be used for prometheus metrics.                                                                                                                                                                                                                          |
182 182
 | `MTG_STATSD_ADDR`             | `--statsd-addr`              |                                   | IP:host addresses of statsd service. No defaults, by defaults we do not send anything there.                                                                                                                                                                                    |
183 183
 | `MTG_STATSD_PORT`             | `--statsd-port`              | `8125`                            | Which port should we use to work with statsd.                                                                                                                                                                                                                                   |
184
-| `MTG_STATSD_NETWORK`          | `--statsd-network`           | `udp`                             | Which protocol should we use to work with statsd. Possible options are `udp` and `tcp`.                                                                                                                                                                                         |
185 184
 | `MTG_STATSD_PREFIX`           | `--statsd-prefix`            | `mtg`                             | Which bucket prefix we should use. For example, if you set `mtg`, then metric `traffic.ingress` would be send as `mtg.traffic.ingress`.                                                                                                                                         |
186 185
 | `MTG_STATSD_TAGS_FORMAT`      | `--statsd-tags-format`       |                                   | Which tags format we should use. By default, we are using default vanilla statsd tags format but if you want to send directly to InfluxDB or Datadog, please specify it there. Possible options are `influxdb` and `datadog`.                                                   |
187 186
 | `MTG_STATSD_TAGS`             | `--statsd-tags`              |                                   | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs.                                                                                                                                                                                 |

+ 12
- 22
config/config.go Vedi File

@@ -9,8 +9,8 @@ import (
9 9
 	"net"
10 10
 
11 11
 	"github.com/alecthomas/units"
12
+	statsd "github.com/smira/go-statsd"
12 13
 	"go.uber.org/zap"
13
-	statsd "gopkg.in/alexcesaro/statsd.v2"
14 14
 )
15 15
 
16 16
 type SecretMode uint8
@@ -47,7 +47,6 @@ const (
47 47
 	OptionTypeStatsBind
48 48
 	OptionTypeStatsNamespace
49 49
 	OptionTypeStatsdAddress
50
-	OptionTypeStatsdNetwork
51 50
 	OptionTypeStatsdTagsFormat
52 51
 	OptionTypeStatsdTags
53 52
 
@@ -65,14 +64,14 @@ const (
65 64
 )
66 65
 
67 66
 type Config struct {
68
-	Bind       *net.TCPAddr `json:"bind"`
69
-	PublicIPv4 *net.TCPAddr `json:"public_ipv4"`
70
-	PublicIPv6 *net.TCPAddr `json:"public_ipv6"`
71
-	StatsBind  *net.TCPAddr `json:"stats_bind"`
72
-	StatsdAddr *net.TCPAddr `json:"stats_addr"`
67
+	Bind             *net.TCPAddr      `json:"bind"`
68
+	PublicIPv4       *net.TCPAddr      `json:"public_ipv4"`
69
+	PublicIPv6       *net.TCPAddr      `json:"public_ipv6"`
70
+	StatsBind        *net.TCPAddr      `json:"stats_bind"`
71
+	StatsdAddr       *net.TCPAddr      `json:"stats_addr"`
72
+	StatsdTagsFormat *statsd.TagFormat `json:"statsd_tags_format"`
73 73
 
74 74
 	StatsNamespace string            `json:"stats_namespace"`
75
-	StatsdNetwork  string            `json:"statsd_network"`
76 75
 	CloakHost      string            `json:"cloak_host"`
77 76
 	StatsdTags     map[string]string `json:"statsd_tags"`
78 77
 
@@ -84,10 +83,9 @@ type Config struct {
84 83
 
85 84
 	MultiplexPerConnection int `json:"multiplex_per_connection"`
86 85
 
87
-	Debug            bool             `json:"debug"`
88
-	Verbose          bool             `json:"verbose"`
89
-	StatsdTagsFormat statsd.TagFormat `json:"statsd_tags_format"`
90
-	SecretMode       SecretMode       `json:"secret_mode"`
86
+	Debug      bool       `json:"debug"`
87
+	Verbose    bool       `json:"verbose"`
88
+	SecretMode SecretMode `json:"secret_mode"`
91 89
 
92 90
 	Secret []byte `json:"secret"`
93 91
 	AdTag  []byte `json:"adtag"`
@@ -125,21 +123,13 @@ func Init(options ...Opt) error { // nolint: gocyclo, funlen
125 123
 			C.StatsNamespace = opt.Value.(string)
126 124
 		case OptionTypeStatsdAddress:
127 125
 			C.StatsdAddr = opt.Value.(*net.TCPAddr)
128
-		case OptionTypeStatsdNetwork:
129
-			value := opt.Value.(string)
130
-			switch value {
131
-			case "udp", "tcp":
132
-				C.StatsdNetwork = value
133
-			default:
134
-				return fmt.Errorf("unknown statsd network %v", value)
135
-			}
136 126
 		case OptionTypeStatsdTagsFormat:
137 127
 			value := opt.Value.(string)
138 128
 			switch value {
139 129
 			case "datadog":
140
-				C.StatsdTagsFormat = statsd.Datadog
130
+				C.StatsdTagsFormat = statsd.TagFormatDatadog
141 131
 			case "influxdb":
142
-				C.StatsdTagsFormat = statsd.InfluxDB
132
+				C.StatsdTagsFormat = statsd.TagFormatInfluxDB
143 133
 			default:
144 134
 				return fmt.Errorf("incorrect statsd tag %s", value)
145 135
 			}

+ 4
- 3
go.mod Vedi File

@@ -7,12 +7,13 @@ require (
7 7
 	github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
8 8
 	github.com/beevik/ntp v0.2.0
9 9
 	github.com/prometheus/client_golang v1.2.1
10
+	github.com/prometheus/procfs v0.0.6 // indirect
11
+	github.com/smira/go-statsd v1.3.1
10 12
 	go.uber.org/multierr v1.4.0 // indirect
11 13
 	go.uber.org/zap v1.12.0
12
-	golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a
14
+	golang.org/x/crypto v0.0.0-20191111213947-16651526fdb4
13 15
 	golang.org/x/net v0.0.0-20191109021931-daa7c04131f5 // indirect
14 16
 	golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4
15
-	golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 // indirect
17
+	golang.org/x/tools v0.0.0-20191112005509-a3f652f18032 // indirect
16 18
 	gopkg.in/alecthomas/kingpin.v2 v2.2.6
17
-	gopkg.in/alexcesaro/statsd.v2 v2.0.0
18 19
 )

+ 11
- 6
go.sum Vedi File

@@ -49,6 +49,8 @@ github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
49 49
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
50 50
 github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
51 51
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
52
+github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
53
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
52 54
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
53 55
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
54 56
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -95,9 +97,13 @@ github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNG
95 97
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
96 98
 github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
97 99
 github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
100
+github.com/prometheus/procfs v0.0.6 h1:0qbH+Yqu/cj1ViVLvEWCP6qMQ4efWUj6bQqOEA0V0U4=
101
+github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
98 102
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
99 103
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
100 104
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
105
+github.com/smira/go-statsd v1.3.1 h1:JalGiHNdK7GqVAPpg7j0Kwp2jZrz/fCg/B4ZuNuBY2w=
106
+github.com/smira/go-statsd v1.3.1/go.mod h1:1srXJ9/pbnN04G8f4F1jUzsGOnwkPKXciyqpewGlkC4=
101 107
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
102 108
 github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
103 109
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -121,8 +127,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
121 127
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
122 128
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
123 129
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
124
-golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a h1:R/qVym5WAxsZWQqZCwDY/8sdVKV1m1WgU4/S5IRQAzc=
125
-golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
130
+golang.org/x/crypto v0.0.0-20191111213947-16651526fdb4 h1:AGVXd+IAyeAb3FuQvYDYQ9+WR2JHm0+C0oYJaU1C4rs=
131
+golang.org/x/crypto v0.0.0-20191111213947-16651526fdb4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
126 132
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
127 133
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
128 134
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -137,6 +143,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
137 143
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
138 144
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
139 145
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
146
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
140 147
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
141 148
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
142 149
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -152,13 +159,11 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
152 159
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
153 160
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
154 161
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
155
-golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 h1:LCmXVkvpQCDj724eX6irUTPCJP5GelFHxqGSWL2D1R0=
156
-golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
162
+golang.org/x/tools v0.0.0-20191112005509-a3f652f18032 h1:Hp/Ke3YMUvqiVTvaoElioq98ROVmHsouhctlE8sVGpo=
163
+golang.org/x/tools v0.0.0-20191112005509-a3f652f18032/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
157 164
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
158 165
 gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
159 166
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
160
-gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc=
161
-gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU=
162 167
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
163 168
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
164 169
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

+ 0
- 6
main.go Vedi File

@@ -72,11 +72,6 @@ var (
72 72
 		"Host:port of statsd server").
73 73
 		Envar("MTG_STATSD_ADDR").
74 74
 		TCP()
75
-	runStatsdNetwork = runCommand.Flag("statsd-network",
76
-		"Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
77
-		Envar("MTG_STATSD_NETWORK").
78
-		Default("udp").
79
-		Enum("udp", "tcp")
80 75
 	runStatsdTagsFormat = runCommand.Flag("statsd-tags-format",
81 76
 		"Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
82 77
 		Envar("MTG_STATSD_TAGS_FORMAT").
@@ -139,7 +134,6 @@ func main() {
139 134
 			config.Opt{Option: config.OptionTypeStatsBind, Value: *runStatsBind},
140 135
 			config.Opt{Option: config.OptionTypeStatsNamespace, Value: *runStatsNamespace},
141 136
 			config.Opt{Option: config.OptionTypeStatsdAddress, Value: *runStatsdAddress},
142
-			config.Opt{Option: config.OptionTypeStatsdNetwork, Value: *runStatsdNetwork},
143 137
 			config.Opt{Option: config.OptionTypeStatsdTagsFormat, Value: *runStatsdTagsFormat},
144 138
 			config.Opt{Option: config.OptionTypeStatsdTags, Value: *runStatsdTags},
145 139
 			config.Opt{Option: config.OptionTypeWriteBufferSize, Value: *runWriteBufferSize},

+ 2
- 13
stats/stats.go Vedi File

@@ -14,20 +14,9 @@ var Stats Interface
14 14
 func Init(ctx context.Context) error {
15 15
 	mux := http.NewServeMux()
16 16
 
17
-	instancePrometheus, err := newStatsPrometheus(mux)
18
-	if err != nil {
19
-		return fmt.Errorf("cannot initialize prometheus: %w", err)
20
-	}
21
-
22
-	stats := []Interface{instancePrometheus}
23
-
17
+	stats := []Interface{newStatsPrometheus(mux)}
24 18
 	if config.C.StatsdAddr != nil {
25
-		instanceStatsd, err := newStatsStatsd()
26
-		if err != nil {
27
-			return fmt.Errorf("cannot inialize statsd: %w", err)
28
-		}
29
-
30
-		stats = append(stats, instanceStatsd)
19
+		stats = append(stats, newStatsStatsd())
31 20
 	}
32 21
 
33 22
 	listener, err := net.Listen("tcp", config.C.StatsBind.String())

+ 9
- 24
stats/stats_prometheus.go Vedi File

@@ -1,7 +1,6 @@
1 1
 package stats
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"net"
6 5
 	"net/http"
7 6
 	"strconv"
@@ -17,7 +16,7 @@ type statsPrometheus struct {
17 16
 	connections         *prometheus.GaugeVec
18 17
 	telegramConnections *prometheus.GaugeVec
19 18
 	traffic             *prometheus.GaugeVec
20
-	crashes             prometheus.Gauge
19
+	crashes             prometheus.Counter
21 20
 	replayAttacks       prometheus.Counter
22 21
 }
23 22
 
@@ -88,7 +87,7 @@ func (s *statsPrometheus) ReplayDetected() {
88 87
 	s.replayAttacks.Inc()
89 88
 }
90 89
 
91
-func newStatsPrometheus(mux *http.ServeMux) (Interface, error) {
90
+func newStatsPrometheus(mux *http.ServeMux) Interface {
92 91
 	registry := prometheus.NewPedanticRegistry()
93 92
 
94 93
 	instance := &statsPrometheus{
@@ -107,7 +106,7 @@ func newStatsPrometheus(mux *http.ServeMux) (Interface, error) {
107 106
 			Name:      "traffic",
108 107
 			Help:      "Traffic passed through the proxy in bytes.",
109 108
 		}, []string{"direction"}),
110
-		crashes: prometheus.NewGauge(prometheus.GaugeOpts{
109
+		crashes: prometheus.NewCounter(prometheus.CounterOpts{
111 110
 			Namespace: config.C.StatsNamespace,
112 111
 			Name:      "crashes",
113 112
 			Help:      "How many crashes happened.",
@@ -119,28 +118,14 @@ func newStatsPrometheus(mux *http.ServeMux) (Interface, error) {
119 118
 		}),
120 119
 	}
121 120
 
122
-	if err := registry.Register(instance.connections); err != nil {
123
-		return nil, fmt.Errorf("cannot register metrics for connections: %w", err)
124
-	}
125
-
126
-	if err := registry.Register(instance.telegramConnections); err != nil {
127
-		return nil, fmt.Errorf("cannot register metrics for telegram connections: %w", err)
128
-	}
129
-
130
-	if err := registry.Register(instance.traffic); err != nil {
131
-		return nil, fmt.Errorf("cannot register metrics for traffic: %w", err)
132
-	}
133
-
134
-	if err := registry.Register(instance.crashes); err != nil {
135
-		return nil, fmt.Errorf("cannot register metrics for crashes: %w", err)
136
-	}
137
-
138
-	if err := registry.Register(instance.replayAttacks); err != nil {
139
-		return nil, fmt.Errorf("cannot register metrics for replays: %w", err)
140
-	}
121
+	registry.MustRegister(instance.connections)
122
+	registry.MustRegister(instance.telegramConnections)
123
+	registry.MustRegister(instance.traffic)
124
+	registry.MustRegister(instance.crashes)
125
+	registry.MustRegister(instance.replayAttacks)
141 126
 
142 127
 	handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
143 128
 	mux.Handle("/", handler)
144 129
 
145
-	return instance, nil
130
+	return instance
146 131
 }

+ 124
- 41
stats/stats_statsd.go Vedi File

@@ -5,23 +5,74 @@ import (
5 5
 	"net"
6 6
 	"strconv"
7 7
 	"strings"
8
+	"sync"
9
+	"time"
8 10
 
9
-	"gopkg.in/alexcesaro/statsd.v2"
11
+	statsd "github.com/smira/go-statsd"
12
+	"go.uber.org/zap"
10 13
 
11 14
 	"mtg/config"
12 15
 	"mtg/conntypes"
13 16
 )
14 17
 
18
+var (
19
+	tagTrafficIngress = &statsStatsdTag{
20
+		name: "ingress",
21
+		tag:  statsd.StringTag("type", "ingress"),
22
+	}
23
+	tagTrafficEgress = &statsStatsdTag{
24
+		name: "egress",
25
+		tag:  statsd.StringTag("type", "egress"),
26
+	}
27
+
28
+	tagConnectionTypeAbridged = &statsStatsdTag{
29
+		name: "abridged",
30
+		tag:  statsd.StringTag("type", "abridged"),
31
+	}
32
+	tagConnectionTypeIntermediate = &statsStatsdTag{
33
+		name: "intermediate",
34
+		tag:  statsd.StringTag("type", "intermediate"),
35
+	}
36
+	tagConnectionTypeSecured = &statsStatsdTag{
37
+		name: "secured",
38
+		tag:  statsd.StringTag("type", "secured"),
39
+	}
40
+
41
+	tagConnectionProtocol4 = &statsStatsdTag{
42
+		name: "ipv4",
43
+		tag:  statsd.StringTag("protocol", "ipv4"),
44
+	}
45
+	tagConnectionProtocol6 = &statsStatsdTag{
46
+		name: "ipv6",
47
+		tag:  statsd.StringTag("protocol", "ipv6"),
48
+	}
49
+)
50
+
51
+type statsStatsdTag struct {
52
+	tag  statsd.Tag
53
+	name string
54
+}
55
+
56
+type statsStatsdLogger struct {
57
+	log *zap.SugaredLogger
58
+}
59
+
60
+func (s *statsStatsdLogger) Printf(msg string, args ...interface{}) {
61
+	s.log.Debugw(fmt.Sprintf(msg, args...))
62
+}
63
+
15 64
 type statsStatsd struct {
16
-	client *statsd.Client
65
+	seen      map[string]struct{}
66
+	seenMutex sync.RWMutex
67
+	client    *statsd.Client
17 68
 }
18 69
 
19 70
 func (s *statsStatsd) IngressTraffic(traffic int) {
20
-	s.client.Count("traffic.ingress", traffic)
71
+	s.gauge("traffic", int64(traffic), tagTrafficIngress)
21 72
 }
22 73
 
23 74
 func (s *statsStatsd) EgressTraffic(traffic int) {
24
-	s.client.Count("traffic.egress", traffic)
75
+	s.gauge("traffic", int64(traffic), tagTrafficEgress)
25 76
 }
26 77
 
27 78
 func (s *statsStatsd) ClientConnected(connectionType conntypes.ConnectionType, addr *net.TCPAddr) {
@@ -32,25 +83,25 @@ func (s *statsStatsd) ClientDisconnected(connectionType conntypes.ConnectionType
32 83
 	s.changeConnections(connectionType, addr, -1)
33 84
 }
34 85
 
35
-func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, value int) {
36
-	labels := [...]string{
37
-		"connections",
38
-		"intermediate",
39
-		"ipv4",
40
-	}
86
+func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, increment int64) {
87
+	tags := make([]*statsStatsdTag, 0, 2)
41 88
 
42 89
 	switch connectionType {
43 90
 	case conntypes.ConnectionTypeAbridged:
44
-		labels[1] = "abridged"
45
-	case conntypes.ConnectionTypeSecure:
46
-		labels[1] = "secured"
91
+		tags = append(tags, tagConnectionTypeAbridged)
92
+	case conntypes.ConnectionTypeIntermediate:
93
+		tags = append(tags, tagConnectionTypeIntermediate)
94
+	default:
95
+		tags = append(tags, tagConnectionTypeSecured)
47 96
 	}
48 97
 
49 98
 	if addr.IP.To4() == nil {
50
-		labels[2] = "ipv6"
99
+		tags = append(tags, tagConnectionProtocol6)
100
+	} else {
101
+		tags = append(tags, tagConnectionProtocol4)
51 102
 	}
52 103
 
53
-	s.client.Count(strings.Join(labels[:], "."), value)
104
+	s.gauge("connections", increment, tags...)
54 105
 }
55 106
 
56 107
 func (s *statsStatsd) TelegramConnected(dc conntypes.DC, addr *net.TCPAddr) {
@@ -61,51 +112,83 @@ func (s *statsStatsd) TelegramDisconnected(dc conntypes.DC, addr *net.TCPAddr) {
61 112
 	s.changeTelegramConnections(dc, addr, -1)
62 113
 }
63 114
 
64
-func (s *statsStatsd) changeTelegramConnections(dc conntypes.DC, addr *net.TCPAddr, value int) {
65
-	labels := [...]string{
66
-		"telegram_connections",
67
-		strconv.Itoa(int(dc)),
68
-		"ipv4",
115
+func (s *statsStatsd) changeTelegramConnections(dc conntypes.DC, addr *net.TCPAddr, increment int64) {
116
+	tags := []*statsStatsdTag{
117
+		{
118
+			name: "dc" + strconv.Itoa(int(dc)),
119
+			tag:  statsd.IntTag("dc", int(dc)),
120
+		},
69 121
 	}
70 122
 
71 123
 	if addr.IP.To4() == nil {
72
-		labels[2] = "ipv6"
124
+		tags = append(tags, tagConnectionProtocol6)
125
+	} else {
126
+		tags = append(tags, tagConnectionProtocol4)
73 127
 	}
74 128
 
75
-	s.client.Count(strings.Join(labels[:], "."), value)
129
+	s.gauge("telegram_connections", increment, tags...)
76 130
 }
77 131
 
78 132
 func (s *statsStatsd) Crash() {
79
-	s.client.Increment("crashes")
133
+	s.gauge("crashes", 1)
80 134
 }
81 135
 
82 136
 func (s *statsStatsd) ReplayDetected() {
83
-	s.client.Increment("replay_attacks")
137
+	s.gauge("replay_attacks", 1)
138
+}
139
+
140
+func (s *statsStatsd) gauge(metric string, value int64, tags ...*statsStatsdTag) {
141
+	key, tagList := s.prepareVals(metric, tags)
142
+	s.initGauge(metric, key, tagList)
143
+	s.client.GaugeDelta(metric, value, tagList...)
144
+}
145
+
146
+func (s *statsStatsd) prepareVals(metric string, tags []*statsStatsdTag) (string, []statsd.Tag) {
147
+	tagList := make([]statsd.Tag, len(tags))
148
+	builder := strings.Builder{}
149
+	builder.WriteString(metric)
150
+
151
+	for i, v := range tags {
152
+		builder.WriteRune('.')
153
+		builder.WriteString(v.name)
154
+		tagList[i] = v.tag
155
+	}
156
+
157
+	return builder.String(), tagList
84 158
 }
85 159
 
86
-func newStatsStatsd() (Interface, error) {
87
-	options := []statsd.Option{
88
-		statsd.Prefix(config.C.StatsNamespace),
89
-		statsd.Network(config.C.StatsdNetwork),
90
-		statsd.Address(config.C.StatsdAddr.String()),
91
-		statsd.TagsFormat(config.C.StatsdTagsFormat),
160
+func (s *statsStatsd) initGauge(metric, key string, tags []statsd.Tag) {
161
+	s.seenMutex.RLock()
162
+	_, ok := s.seen[key]
163
+	s.seenMutex.RUnlock()
164
+
165
+	if ok {
166
+		return
92 167
 	}
93 168
 
94
-	if len(config.C.StatsdTags) > 0 {
95
-		tags := make([]string, len(config.C.StatsdTags)*2)
96
-		for k, v := range config.C.StatsdTags {
97
-			tags = append(tags, k, v)
98
-		}
169
+	s.seenMutex.Lock()
170
+	defer s.seenMutex.Unlock()
99 171
 
100
-		options = append(options, statsd.Tags(tags...))
172
+	if _, ok = s.seen[key]; !ok {
173
+		s.seen[key] = struct{}{}
174
+		s.client.Gauge(metric, 0, tags...)
101 175
 	}
176
+}
102 177
 
103
-	client, err := statsd.New(options...)
104
-	if err != nil {
105
-		return nil, fmt.Errorf("cannot initialize a client: %w", err)
178
+func newStatsStatsd() Interface {
179
+	prefix := strings.TrimSuffix(config.C.StatsNamespace, ".") + "."
180
+	logger := &statsStatsdLogger{
181
+		log: zap.S().Named("stats").Named("statsd"),
106 182
 	}
107 183
 
108 184
 	return &statsStatsd{
109
-		client: client,
110
-	}, nil
185
+		seen: make(map[string]struct{}),
186
+		client: statsd.NewClient(config.C.StatsdAddr.String(),
187
+			statsd.SendLoopCount(2),
188
+			statsd.ReconnectInterval(10*time.Second),
189
+			statsd.Logger(logger),
190
+			statsd.MetricPrefix(prefix),
191
+			statsd.TagStyle(config.C.StatsdTagsFormat),
192
+		),
193
+	}
111 194
 }

Loading…
Annulla
Salva