Monitorer son application Go en local
Comment récupérer des métriques sur son application Golang tournant localement
Récemment, après plusieurs jours en production, nous avons détecté au boulot que notre pod Cercat semblait avoir une memory leak.
Rien de complexe dans notre cas (ouf), cela a facilement été réglé à coup de profiles Go mais une question s’est posée : “Aurais-je pu le détecter avant d’envoyer en prod en sachant que l'évolution de la consommation mémoire était relativement lente?"
Je me suis donc mis en tête d’avoir une solution clé en main pour monitorer en local une application Go lors de son développement.
L’idée, très simple au final, est d’utiliser une instance de Netdata dans un Docker qui appelle l’endpoint expvar de mon application Go.
Micro tuto pour comprendre le principe :
-
Préparer notre application
Un micro code pour l’exemple :
package main import ( "expvar" // package pour exposer les métriques Go par défaut et notre métrique custom "math/rand" "net/http" "time" ) func main() { fake := expvar.NewFloat("custom.fake") // une métrique custom complètement fausse go http.ListenAndServe(":1111", nil) // on démarre un serveur http sur le port 1111 for { // une boucle qui met à jour aléatoirement notre métrique custom fake.Set((rand.Float64() * 10) - 5) time.Sleep(time.Duration(rand.Intn(3)) * time.Second) } }
Le code est commenté pour comprendre à quoi sert chaque ligne.
-
On prépare la configuration de Netdata
go_expvar.conf
'golang-app': name : 'golang-app' # le nom de notre app Go dans Netdata url : 'http://golang-app:1111/debug/vars' # le port est à adapter en fonction de l'application collect_memstats: true # on active la collecte des métriques mémoires extra_charts: # la collecte de notre métrique custom - id: "custom" options: name: fake title: "custom" units: no-unit family: custom context: expvar.custom.fake chart_type: line lines: - {expvar_key: 'custom.fake', expvar_type: float, id: custom_fake}
python.d.conf
go_expvar: yes # active le monitoring des applications Go
-
On démarre le tout via docker-compose
docker-compose.yaml
--- version: "3" services: netdata: image: netdata/netdata:latest container_name: netdata ports: - "19999:19999" volumes: - "${PWD}/python.d.conf:/etc/netdata/python.d.conf:ro" # pour activer le monitoring des applications GO - "${PWD}/go_expvar.conf:/etc/netdata/python.d/go_expvar.conf:ro" # pour configurer la collecte des métriques des applications Go - "/etc/passwd:/host/etc/passwd:ro" - "/etc/group:/host/etc/group:ro" - "/proc:/host/proc:ro" - "/sys:/host/sys:ro" - "/var/run/docker.sock:/var/run/docker.sock:ro" # pour moniter le Docker Go cap_add: - SYS_PTRACE security_opt: - apparmor:unconfined golang-app: image: golang:alpine container_name: golang-app ports: - "1111:1111" # le port d'écoute de notre application, à adapter volumes: - "${PWD}:/app" working_dir: /app command: go run main.go # la commande pour lancer l'application, à adapter
Le plus important est d’adapter le port d'écoute et la commande de démarrage en fonction de votre application.
On démarre tout :
docker-compose -f docker-compose.yaml up -d
On vérifie que tout est bien démarré :
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5f9a07fa2e1f netdata/netdata:latest "/usr/sbin/run.sh" About a minute ago Up About a minute (healthy) 0.0.0.0:19999->19999/tcp netdata 4e9d30d12bec golang:alpine "go run main.go" 5 days ago Up About a minute 0.0.0.0:1111->1111/tcp golang-app
L’instance Netdata est accessible via http://localhost:19999.
Après quelques secondes on obtient nos métriques.
Les métriques du container de notre application :
Les métriques expvar de notre application :
Notre métrique custom :
-
Mettre à jour notre application
C’est très simple, il suffit de redémarrer le container Go :
$ docker restart 4e9d30d12bec
Enjoy