MTProto Proxy-Statistiksammlung

Inhalt
  • Hintergrund
  • Statistiksammlung
  • Statistikanzeige
  • Visualisierung und Statistik
  • Scannen
  • Fazit


Hintergrund


Hallo habr, Telegramme sind jetzt auf dem Höhepunkt der Popularität, alle Skandale, Intrigen und Sperren drehen sich um ihn, in Verbindung mit dem Telegramm eine eigene Version des Proxys namens MTProto Proxy herausgebracht wurde, die bei der Umgehung der Sperre helfen soll. Die vom Telegramm MTProto Proxy bereitgestellten Überwachungsdienste ermöglichen es jedoch nicht, Statistiken in Echtzeit zu beobachten und zu erfassen, um ihre Änderungen zu überwachen. Daher werden wir das Problem selbst lösen.

Statistiksammlung


Auf der offiziellen MTProto-Proxy-Seite im Docker Hub heißt es, dass wir den docker exec mtproto-proxy curl http://localhost:2398/stats , um Statistiken direkt vom MTProto-Proxy abzurufen, der sich im Container befindet. Unser Code sieht also so aus.

 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 auf demselben Docker Hub wie die Anzahl der eingehenden Clientverbindungen angezeigt

Statistikanzeige


Als nächstes müssen wir die aktuelle Anzahl der Benutzer in einer einfachen und bequemen Form anzeigen, wir werden sie an den Browser ausgeben.

 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) } 

was ist init
init wird in jedem Fall vor dem Aufruf von main aufgerufen

Wenn wir jetzt zur IP-Adresse unseres MTProto-Proxys gehen, können wir die aktuelle Anzahl der Clients sehen.

Bild

Visualisierung und Statistik


Es gibt viele Möglichkeiten, Statistiken von Datadog , Zabbix , Grafana , Graphite zu visualisieren und zu pflegen. Ich werde Datadog verwenden. Mit dem Befehl go get -u github.com/DataDog/datadog-go/statsd importieren go get -u github.com/DataDog/datadog-go/statsd die statsd Bibliothek und verwenden sie im 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) } 


Es bleibt alles in einem Docker-Image zu sammeln

 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"] 

Scannen


Zuerst müssen wir den Container mit dem Datadog-Agenten starten

 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 

WICHTIG, damit wir dem Agenten unsere Daten senden können, müssen Sie für die Umgebungsvariable DD_DOGSTATSD_NON_LOCAL_TRAFFIC den DD_DOGSTATSD_NON_LOCAL_TRAFFIC true DD_DOGSTATSD_NON_LOCAL_TRAFFIC

Als nächstes müssen wir mit dem docker inspect dd-agent die IP des Containers docker inspect dd-agent , um Daten an ihn zu senden

Bild

und starten Sie unseren MTProto-Proxy, indem Sie ihn mit einer Brücke mit dem Agentencontainer verbinden

 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 

Und in wenigen Minuten können wir bereits ein Diagramm erstellen, indem wir die gewünschte Metrik und Quelle auswählen (das Tag, das beim Starten des Containers mit MTProto Proxy angegeben wird).

Bild

und zeigen Sie unsere Statistiken darauf

Bild

Lebendes Beispiel

Fazit


Für mich entdeckte ich neue Werkzeuge für die bequeme Arbeit mit Daten, lernte deren große Vielfalt kennen und wählte etwas, das meinem Geschmack entsprach.

Vielen Dank für Ihre Aufmerksamkeit. Ich schlage vor, dass alle ihre Meinungen, Kommentare und Vorschläge in den Kommentaren teilen.

Github-Repository

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


All Articles