Collecte des statistiques du proxy MTProto

Table des matières
  • Contexte
  • Collecte de statistiques
  • Affichage des statistiques
  • Visualisation et statistiques
  • Numériser
  • Conclusion


Contexte


Salut habr, les télégrammes sont maintenant au sommet de la popularité, tous les scandales, intrigues, verrous tournent autour de lui, à propos desquels le télégramme a déployé sa propre version du proxy appelé MTProto Proxy, qui est conçu pour aider à contourner le verrou. Cependant, les services de surveillance fournis par le télégramme MTProto Proxy ne permettent pas d'observer les statistiques en temps réel et de les collecter pour surveiller ses changements, nous allons donc résoudre le problème par nous-mêmes.

Collecte de statistiques


La page officielle du proxy MTProto sur le Docker Hub indique que nous pouvons utiliser la commande docker exec mtproto-proxy curl http://localhost:2398/stats pour obtenir des statistiques directement à partir du proxy MTProto qui se trouve dans le conteneur, donc notre code ressemblera à ceci.

 package main import ( "io/ioutil" "net/http" "strings" "time" ) type User struct { Num string } var Users User func CurrenUsers() (err error) { //   response, err := http.Get(`http://localhost:2398/stats`) if err != nil { return } body, err := ioutil.ReadAll(response.Body) if err != nil { return } defer response.Body.Close() stat := strings.Split(string(body), "\n") for _, item := range stat { //        //     if strings.HasPrefix(item, `total_special_connections`) { Users.Num = strings.Split(item, "\t")[1] } } return nil } func main() { for t := time.Tick(10 * time.Second); ; <-t { if err := CurrenUsers(); err != nil { continue } } } 

total_special_connections indiqué sur le même Docker Hub que le nombre de connexions client entrantes

Affichage des statistiques


Ensuite, nous devons afficher le nombre actuel d'utilisateurs sous une forme simple et pratique, nous le publierons dans le navigateur.

 package main import ( "html/template" "io/ioutil" "net/http" "strings" "time" ) type User struct { Num string } type HTML struct { IndexPage string } var Users User var IndexTemplate = HTML{ IndexPage: `<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"> <title>Stats</title> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> </head> <body> <div class="container-fluid"> <div class="row justify-content-center text-center" style="margin-top: 20%"> <h1>Count of current users of MTProto Proxy: {{.Num}}</h1> </div> </div> </body> </html>`, } func CurrenUsers() (err error) { //   response, err := http.Get(`http://localhost:2398/stats`) if err != nil { return } body, err := ioutil.ReadAll(response.Body) if err != nil { return } defer response.Body.Close() stat := strings.Split(string(body), "\n") for _, item := range stat { //        //     if strings.HasPrefix(item, `total_special_connections`) { Users.Num = strings.Split(item, "\t")[1] } } return nil } func sendStat(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { t := template.Must(template.New("indexpage").Parse(IndexTemplate.IndexPage)) t.Execute(w, Users) } } func init() { go func() { for t := time.Tick(10 * time.Second); ; <-t { if err := CurrenUsers(); err != nil { continue } } }() } func main() { http.HandleFunc("/", sendStat) http.ListenAndServe(":80", nil) } 

qu'est-ce que init
init sera en tout cas appelé avant d'appeler main

Maintenant, en allant à l'adresse IP de notre proxy MTProto, nous pouvons voir le nombre actuel de clients.

image

Visualisation et statistiques


Il existe de nombreuses options pour visualiser et maintenir les statistiques de Datadog , Zabbix , Grafana , Graphite . J'utiliserai Datadog. En utilisant la commande go get -u github.com/DataDog/datadog-go/statsd importons la bibliothèque statsd et l'utilisons dans le code.

 package main import ( "html/template" "io/ioutil" "net/http" "os" "strconv" "strings" "time" "github.com/DataDog/datadog-go/statsd" ) var ( datadogIP = os.Getenv("DDGIP") tagName = os.Getenv("TGN") t, _ = strconv.Atoi(os.Getenv("TIMEOUT")) timeout = time.Duration(t) * time.Second ) type User struct { Num string } type HTML struct { IndexPage string } var Users User var IndexTemplate = HTML{ IndexPage: `<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"> <title>Stats</title> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> </head> <body> <div class="container-fluid"> <div class="row justify-content-center text-center" style="margin-top: 20%"> <h1>Count of current users of MTProto Proxy: {{.Num}}</h1> </div> </div> </body> </html>`, } func (u User) convert() int64 { num, _ := strconv.Atoi(u.Num) return int64(num) } func CurrenUsers() (err error) { //   response, err := http.Get(`http://localhost:2398/stats`) if err != nil { return } body, err := ioutil.ReadAll(response.Body) if err != nil { return } defer response.Body.Close() stat := strings.Split(string(body), "\n") for _, item := range stat { //        //     if strings.HasPrefix(item, `total_special_connections`) { Users.Num = strings.Split(item, "\t")[1] } } return nil } func sendStat(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { t := template.Must(template.New("indexpage").Parse(IndexTemplate.IndexPage)) t.Execute(w, Users) } } func init() { if t == 0 { timeout = 10 * time.Second } go func() { for t := time.Tick(timeout); ; <-t { if err := CurrenUsers(); err != nil { continue } } }() //    Datadog go func() error { c, err := statsd.New(datadogIP + ":8125") if err != nil || len(datadogIP) == 0 { return err } c.Namespace = "mtproto." c.Tags = append(c.Tags, tagName) for t := time.Tick(timeout); ; <-t { c.Count("users.count", Users.convert(), nil, 1) } }() } func main() { http.HandleFunc("/", sendStat) http.ListenAndServe(":80", nil) } 


Il reste à tout collecter dans une image docker

 FROM telegrammessenger/proxy COPY mtproto_proxy_stat . RUN echo "$(tail -n +2 run.sh)" > run.sh && echo '#!/bin/bash\n./mtproto_proxy_stat & disown' | cat - run.sh > temp && mv temp run.sh CMD [ "/bin/sh", "-c", "/bin/bash /run.sh"] 

Numériser


Nous devons d'abord démarrer le conteneur avec l'agent Datadog

 docker run -d --name dd-agent -v /var/run/docker.sock:/var/run/docker.sock:ro -v /proc/:/host/proc/:ro -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro -e DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true -e DD_API_KEY=_ datadog/agent:latest 

IMPORTANT pour que nous puissions envoyer à l'agent nos données, vous devez définir true pour la variable d'environnement DD_DOGSTATSD_NON_LOCAL_TRAFFIC

Ensuite, en utilisant la commande docker inspect dd-agent nous devons regarder l'IP du conteneur pour lui envoyer des données

image

et démarrez notre proxy MTProto en le connectant avec un pont au conteneur d'agent

 docker run -d -p 443:443 -p 80:80 -e WORKERS=16 -e DDGIP=172.17.0.2 -e TGN=mtproto:main --link=dd-agent --name=mtproto --restart=always -v proxy-config:/data trigun117/mtproto_proxy_stat 

Et en quelques minutes, nous pouvons déjà créer un graphique en sélectionnant la métrique et la source souhaitées (la balise qui est spécifiée lors du démarrage du conteneur avec MTProto Proxy)

image

et afficher nos statistiques à ce sujet

image

Exemple vivant

Conclusion


Pour ma part, j'ai découvert de nouveaux outils pour un travail pratique avec les données, pris connaissance de leur grande variété et choisi quelque chose qui convient à mon goût.

Merci de votre attention, je suggère à chacun de partager ses opinions, commentaires et suggestions dans les commentaires.

Dépôt Github

Source: https://habr.com/ru/post/fr416087/


All Articles