Parcourir la source

Merge pull request #47 from 9seconds/prometheus

Prometheus integration
tags/0.15^2
Sergey Arkhipov il y a 7 ans
Parent
révision
4695a0c433
Aucun compte lié à l'adresse e-mail de l'auteur
8 fichiers modifiés avec 138 ajouts et 2 suppressions
  1. 12
    0
      README.md
  2. 5
    1
      config/config.go
  3. 9
    0
      go.mod
  4. 18
    0
      go.sum
  5. 7
    1
      main.go
  6. 5
    0
      stats/init.go
  7. 80
    0
      stats/prometheus.go
  8. 2
    0
      stats/server.go

+ 12
- 0
README.md Voir le fichier

@@ -160,6 +160,7 @@ supported environment variables:
160 160
 | `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`.                                                                                                                                    |
161 161
 | `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`.                                              |
162 162
 | `MTG_STATSD_TAGS`        | `--statsd-tags`        |                                   | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs.                                                                                                                                                                            |
163
+| `MTG_PROMETHEUS_PREFIX`  | `--prometheus-prefix`  | `mtg`                             | Which namespace should be used for prometheus metrics.                                                                                                                                                                                                                     |
163 164
 | `MTG_BUFFER_WRITE`       | `-w`, `--write-buffer` | `65536`                           | The size of TCP write buffer in bytes. Write buffer is the buffer for messages which are going from client to Telegram.                                                                                                                                                    |
164 165
 | `MTG_BUFFER_READ`        | `-r`, `--read-buffer`  | `131072`                          | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client.                                                                                                                                                                      |
165 166
 | `MTG_SECURE_ONLY`        | `-s`, `--secure-only`  | `false`                           | Support only clients with secure mode (i.e only clients with dd-secrets).                                                                                                                                                                                                  |
@@ -235,3 +236,14 @@ All metrics are gauges. Here is the list of metrics and their meaning:
235 236
 All metrics are prefixed with given prefix. Default prefix is `mtg`.
236 237
 With such prefix metric name `traffic.ingress`, for example, would be
237 238
 `mtg.traffic.ingress`.
239
+
240
+
241
+# Prometheus integration
242
+
243
+[Prometheus](https://prometheus.io) integration comes out of
244
+the box, you do not need to setup anything special. Prometheus
245
+scrape endpoint lives on the same IP/port where generic stats
246
+service (`http://${MTG_STATS_IP}:${MTG_STATS_PORT}`) but on
247
+`/prometheus` path. So, if you access http stats service as `curl
248
+http://localhost:3129/`, then your prometheus endpoint is `curl
249
+http://localhost:3129/prometheus/`.

+ 5
- 1
config/config.go Voir le fichier

@@ -38,6 +38,9 @@ type Config struct {
38 38
 		TagsFormat statsd.TagFormat
39 39
 		Enabled    bool
40 40
 	}
41
+	Prometheus struct {
42
+		Prefix string
43
+	}
41 44
 
42 45
 	Secret []byte
43 46
 	AdTag  []byte
@@ -116,7 +119,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
116 119
 	bindIP, publicIPv4, publicIPv6, statsIP net.IP,
117 120
 	bindPort, publicIPv4Port, publicIPv6Port, statsPort, statsdPort uint16,
118 121
 	statsdIP, statsdNetwork, statsdPrefix, statsdTagsFormat string,
119
-	statsdTags map[string]string,
122
+	statsdTags map[string]string, prometheusPrefix string,
120 123
 	secureOnly bool,
121 124
 	secret, adtag []byte) (*Config, error) {
122 125
 	secureMode := secureOnly
@@ -174,6 +177,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo
174 177
 		ReadBufferSize:  int(readBufferSize),
175 178
 		WriteBufferSize: int(writeBufferSize),
176 179
 	}
180
+	conf.Prometheus.Prefix = prometheusPrefix
177 181
 
178 182
 	if statsdIP != "" {
179 183
 		conf.StatsD.Enabled = true

+ 9
- 0
go.mod Voir le fichier

@@ -4,20 +4,29 @@ require (
4 4
 	github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
5 5
 	github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
6 6
 	github.com/beevik/ntp v0.2.0
7
+	github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
7 8
 	github.com/davecgh/go-spew v1.1.1 // indirect
8 9
 	github.com/dustin/go-humanize v1.0.0
9 10
 	github.com/gofrs/uuid v3.1.0+incompatible
11
+	github.com/gogo/protobuf v1.1.1 // indirect
12
+	github.com/golang/protobuf v1.2.0 // indirect
10 13
 	github.com/juju/errors v0.0.0-20181012004132-a4583d0a56ea
11 14
 	github.com/juju/loggo v0.0.0-20180524022052-584905176618 // indirect
12 15
 	github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 // indirect
13 16
 	github.com/kr/pretty v0.1.0 // indirect
17
+	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
14 18
 	github.com/pkg/errors v0.8.0 // indirect
15 19
 	github.com/pmezard/go-difflib v1.0.0 // indirect
20
+	github.com/prometheus/client_golang v0.9.0
21
+	github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
22
+	github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37 // indirect
23
+	github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d // indirect
16 24
 	github.com/stretchr/testify v1.2.2
17 25
 	go.uber.org/atomic v1.3.2 // indirect
18 26
 	go.uber.org/multierr v1.1.0 // indirect
19 27
 	go.uber.org/zap v1.9.1
20 28
 	golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 // indirect
29
+	golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
21 30
 	gopkg.in/alecthomas/kingpin.v2 v2.2.6
22 31
 	gopkg.in/alexcesaro/statsd.v2 v2.0.0
23 32
 	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect

+ 18
- 0
go.sum Voir le fichier

@@ -4,12 +4,18 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZq
4 4
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
5 5
 github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
6 6
 github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
7
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
8
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
7 9
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8 10
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9 11
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
10 12
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
11 13
 github.com/gofrs/uuid v3.1.0+incompatible h1:q2rtkjaKT4YEr6E1kamy0Ha4RtepWlQBedyHx0uzKwA=
12 14
 github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
15
+github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
16
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
17
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
18
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
13 19
 github.com/juju/errors v0.0.0-20181012004132-a4583d0a56ea h1:g2k+8WR7cHch4g0tBDhfiEvAp7fXxTNBiD1oC1Oxj3E=
14 20
 github.com/juju/errors v0.0.0-20181012004132-a4583d0a56ea/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
15 21
 github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=
@@ -21,10 +27,20 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
21 27
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
22 28
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
23 29
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
30
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
31
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
24 32
 github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
25 33
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
26 34
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
27 35
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
36
+github.com/prometheus/client_golang v0.9.0 h1:tXuTFVHC03mW0D+Ua1Q2d1EAVqLTuggX50V0VLICCzY=
37
+github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
38
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
39
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
40
+github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37 h1:Y7YdJ9Xb3MoQOzAWXnDunAJYpvhVwZdTirNfGUgPKaA=
41
+github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
42
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
43
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
28 44
 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
29 45
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
30 46
 go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
@@ -35,6 +51,8 @@ go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
35 51
 go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
36 52
 golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w=
37 53
 golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
54
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
55
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
38 56
 gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
39 57
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
40 58
 gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc=

+ 7
- 1
main.go Voir le fichier

@@ -110,6 +110,12 @@ var (
110 110
 		Envar("MTG_STATSD_TAGS").
111 111
 		StringMap()
112 112
 
113
+	prometheusPrefix = app.Flag("prometheus-prefix",
114
+		"Which namespace to use to send stats to Prometheus.").
115
+		Envar("MTG_PROMETHEUS_PREFIX").
116
+		Default("mtg").
117
+		String()
118
+
113 119
 	writeBufferSize = app.Flag("write-buffer",
114 120
 		"Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
115 121
 		Short('w').
@@ -151,7 +157,7 @@ func main() { // nolint: gocyclo
151 157
 		*bindIP, *publicIPv4, *publicIPv6, *statsIP,
152 158
 		*bindPort, *publicIPv4Port, *publicIPv6Port, *statsPort, *statsdPort,
153 159
 		*statsdIP, *statsdNetwork, *statsdPrefix, *statsdTagsFormat,
154
-		*statsdTags, *secureOnly,
160
+		*statsdTags, *prometheusPrefix, *secureOnly,
155 161
 		*secret, *adtag,
156 162
 	)
157 163
 	if err != nil {

+ 5
- 0
stats/init.go Voir le fichier

@@ -15,6 +15,11 @@ func Init(conf *config.Config) error {
15 15
 		}
16 16
 		go client.run()
17 17
 	}
18
+	prometheus, err := newPrometheus(conf)
19
+	if err != nil {
20
+		return errors.Annotate(err, "Cannot initialize prometheus client")
21
+	}
22
+	go prometheus.run()
18 23
 
19 24
 	go NewStats(conf).start()
20 25
 	go startServer(conf)

+ 80
- 0
stats/prometheus.go Voir le fichier

@@ -0,0 +1,80 @@
1
+package stats
2
+
3
+import (
4
+	"time"
5
+
6
+	"github.com/juju/errors"
7
+	"github.com/prometheus/client_golang/prometheus"
8
+
9
+	"github.com/9seconds/mtg/config"
10
+)
11
+
12
+const prometheusPollTime = time.Second
13
+
14
+type prometheusExporter struct {
15
+	connections *prometheus.GaugeVec
16
+	traffic     *prometheus.GaugeVec
17
+	speed       *prometheus.GaugeVec
18
+	crashes     prometheus.Gauge
19
+}
20
+
21
+func (p *prometheusExporter) run() {
22
+	for range time.Tick(prometheusPollTime) {
23
+		instance := GetStats()
24
+
25
+		p.connections.WithLabelValues("abridged", "v4").Set(float64(instance.Connections.Abridged.IPv4))
26
+		p.connections.WithLabelValues("abridged", "v6").Set(float64(instance.Connections.Abridged.IPv6))
27
+		p.connections.WithLabelValues("intermediate", "v4").Set(float64(instance.Connections.Intermediate.IPv4))
28
+		p.connections.WithLabelValues("intermediate", "v6").Set(float64(instance.Connections.Intermediate.IPv6))
29
+		p.connections.WithLabelValues("secure", "v4").Set(float64(instance.Connections.Secure.IPv4))
30
+		p.connections.WithLabelValues("secure", "v6").Set(float64(instance.Connections.Secure.IPv6))
31
+		p.traffic.WithLabelValues("ingress").Set(float64(instance.Traffic.ingress))
32
+		p.traffic.WithLabelValues("egress").Set(float64(instance.Traffic.egress))
33
+		p.speed.WithLabelValues("ingress").Set(float64(instance.Speed.ingress))
34
+		p.speed.WithLabelValues("egress").Set(float64(instance.Speed.egress))
35
+		p.crashes.Set(float64(instance.Crashes))
36
+	}
37
+}
38
+
39
+func newPrometheus(conf *config.Config) (*prometheusExporter, error) {
40
+	connections := prometheus.NewGaugeVec(prometheus.GaugeOpts{
41
+		Namespace: conf.Prometheus.Prefix,
42
+		Name:      "connections",
43
+		Help:      "Current number of connections to the proxy.",
44
+	}, []string{"type", "protocol"})
45
+	traffic := prometheus.NewGaugeVec(prometheus.GaugeOpts{
46
+		Namespace: conf.Prometheus.Prefix,
47
+		Name:      "traffic",
48
+		Help:      "Traffic passed through the proxy in bytes.",
49
+	}, []string{"direction"})
50
+	speed := prometheus.NewGaugeVec(prometheus.GaugeOpts{
51
+		Namespace: conf.Prometheus.Prefix,
52
+		Name:      "speed",
53
+		Help:      "Current throughput in bytes per second.",
54
+	}, []string{"direction"})
55
+	crashes := prometheus.NewGauge(prometheus.GaugeOpts{
56
+		Namespace: conf.Prometheus.Prefix,
57
+		Name:      "crashes",
58
+		Help:      "How many crashes happened.",
59
+	})
60
+
61
+	if err := prometheus.Register(connections); err != nil {
62
+		return nil, errors.Annotate(err, "Cannot register connections collector")
63
+	}
64
+	if err := prometheus.Register(traffic); err != nil {
65
+		return nil, errors.Annotate(err, "cannot register traffic collector")
66
+	}
67
+	if err := prometheus.Register(speed); err != nil {
68
+		return nil, errors.Annotate(err, "cannot register speed collector")
69
+	}
70
+	if err := prometheus.Register(crashes); err != nil {
71
+		return nil, errors.Annotate(err, "cannot register crashes collector")
72
+	}
73
+
74
+	return &prometheusExporter{
75
+		connections: connections,
76
+		traffic:     traffic,
77
+		speed:       speed,
78
+		crashes:     crashes,
79
+	}, nil
80
+}

+ 2
- 0
stats/server.go Voir le fichier

@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"net/http"
6 6
 
7
+	"github.com/prometheus/client_golang/prometheus/promhttp"
7 8
 	"go.uber.org/zap"
8 9
 
9 10
 	"github.com/9seconds/mtg/config"
@@ -32,6 +33,7 @@ func startServer(conf *config.Config) {
32 33
 			log.Errorw("Cannot encode json", "error", err)
33 34
 		}
34 35
 	})
36
+	http.Handle("/prometheus/", promhttp.Handler())
35 37
 
36 38
 	if err := http.ListenAndServe(conf.StatAddr(), nil); err != nil {
37 39
 		log.Fatalw("Stats server has been stopped", "error", err)

Chargement…
Annuler
Enregistrer