Pouet

Wake me up before you code Go!

Monitorer son application Go en local

Comment récupérer des métriques sur son application Golang tournant localement

Issif

3 minutes

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

Cercat memory leak

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 :

  1. 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.

  2. 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
    
  3. 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 :

    Netdata Golang container

    Les métriques expvar de notre application :

    Netdata Golang container

    Notre métrique custom :

    Netdata Golang container
  4. Mettre à jour notre application

    C’est très simple, il suffit de redémarrer le container Go :

    $ docker restart 4e9d30d12bec
    

Enjoy

Posts récents

Voir plus

Catégories

A propos

Du Go, de l'AWS et autres par un SRE/FinOps