雑なメモ書き

気楽にいきます

appengineでmemstatsしたかった

  • appengineのバージョンが古いとデータが取れなかったりするので
  • こちらのコードから必要そうな処理をお借りしました
  • https://github.com/google/gops
package hello

import (
    "encoding/json"
    "fmt"
    "net/http"
    "runtime"
    "time"

    "google.golang.org/appengine"
)

func formatBytes(val uint64) string {
    return fmt.Sprintf("%d", val)
}

func main() {
    http.HandleFunc("/", handle)
    http.HandleFunc("/memstats", handleMemStats)
    appengine.Main()
}

func handle(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, world!")
}

type responseMemStats struct {
    Alloc        string `json:"alloc"`
    TotalAlloc   string `json:"total-alloc"`
    Sys          string `json:"sys"`
    Lookups      string `json:"lookups"`
    Mallocs      string `json:"mallocs"`
    Frees        string `json:"frees"`
    HeapAlloc    string `json:"heap-alloc"`
    HeapSys      string `json:"heap-sys"`
    HeapIdle     string `json:"heap-idle"`
    HeapInuse    string `json:"heap-in-use"`
    HeapReleased string `json:"heap-released"`
    HeapObjects  string `json:"heap-objects"`
    StackInuse   string `josn:"stack-in-use"`
    StackSys     string `json:"stack-sys"`
    MSpanInuse   string `json:"stack-mspan-inuse"`
    MSpanSys     string `json:"stack-mspan-sys"`
    MCacheInuse  string `json:"stack-mcache-inuse"`
    MCacheSys    string `json:"stack-mcache-sys"`
    OtherSys     string `json:"other-sys"`
    GCSys        string `json:"gc-sys"`
    NextGC       string `json:"next-gc"`
    LastGC       string `json:"last-gc"`
    PauseTotalNs string `json:"gc-pause-total"`
    Pause        string `json:"gc-pause"`
    NumGC        string `json:"num-gc"`
    EnableGC     string `json:"enable-gc"`
    DebugGC      string `json:"debug-gc"`
}

func handleMemStats(w http.ResponseWriter, r *http.Request) {
    var s runtime.MemStats
    runtime.ReadMemStats(&s)
    lastGC := "-"
    if s.LastGC != 0 {
        lastGC = fmt.Sprint(time.Unix(0, int64(s.LastGC)))
    }
    responseMemStats := &responseMemStats{
        Alloc:        formatBytes(s.Alloc),
        TotalAlloc:   formatBytes(s.TotalAlloc),
        Sys:          formatBytes(s.Sys),
        Lookups:      fmt.Sprintf("%v", s.Lookups),
        Mallocs:      fmt.Sprintf("%v", s.Mallocs),
        Frees:        fmt.Sprintf("%v", s.Frees),
        HeapAlloc:    formatBytes(s.HeapAlloc),
        HeapSys:      formatBytes(s.HeapSys),
        HeapIdle:     formatBytes(s.HeapIdle),
        HeapInuse:    formatBytes(s.HeapInuse),
        HeapReleased: formatBytes(s.HeapReleased),
        HeapObjects:  fmt.Sprintf("%v", s.HeapObjects),
        StackInuse:   formatBytes(s.StackInuse),
        StackSys:     formatBytes(s.StackSys),
        MSpanInuse:   formatBytes(s.MSpanInuse),
        MSpanSys:     formatBytes(s.MSpanSys),
        MCacheInuse:  formatBytes(s.MCacheInuse),
        MCacheSys:    formatBytes(s.MCacheSys),
        OtherSys:     formatBytes(s.OtherSys),
        GCSys:        formatBytes(s.GCSys),
        NextGC:       formatBytes(s.NextGC),
        LastGC:       lastGC,
        PauseTotalNs: fmt.Sprintf("%v", time.Duration(s.PauseTotalNs)),
        Pause:        fmt.Sprintf("%v", s.PauseNs[(s.NumGC+255)%256]),
        NumGC:        fmt.Sprintf("%v", s.NumGC),
        EnableGC:     fmt.Sprintf("%v", s.EnableGC),
        DebugGC:      fmt.Sprintf("%v", s.DebugGC),
    }
    json, err := json.Marshal(responseMemStats)

    if err != nil {
        fmt.Fprint(w, err.Error())
        return
    }
    fmt.Fprint(w, string(json))
}

こんな感じでserverを立てて

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "reflect"
    "strings"
)

type responseMemStats struct {
    Alloc        string `json:"alloc"`
    TotalAlloc   string `json:"total-alloc"`
    Sys          string `json:"sys"`
    Lookups      string `json:"lookups"`
    Mallocs      string `json:"mallocs"`
    Frees        string `json:"frees"`
    HeapAlloc    string `json:"heap-alloc"`
    HeapSys      string `json:"heap-sys"`
    HeapIdle     string `json:"heap-idle"`
    HeapInuse    string `json:"heap-in-use"`
    HeapReleased string `json:"heap-released"`
    HeapObjects  string `json:"heap-objects"`
    StackInuse   string `josn:"stack-in-use"`
    StackSys     string `json:"stack-sys"`
    MSpanInuse   string `json:"stack-mspan-inuse"`
    MSpanSys     string `json:"stack-mspan-sys"`
    MCacheInuse  string `json:"stack-mcache-inuse"`
    MCacheSys    string `json:"stack-mcache-sys"`
    OtherSys     string `json:"other-sys"`
    GCSys        string `json:"gc-sys"`
    NextGC       string `json:"next-gc"`
    LastGC       string `json:"last-gc"`
    PauseTotalNs string `json:"gc-pause-total"`
    Pause        string `json:"gc-pause"`
    NumGC        string `json:"num-gc"`
    EnableGC     string `json:"enable-gc"`
    DebugGC      string `json:"debug-gc"`
}

func main() {
    targetFields := map[string]bool{
        "Alloc":      true,
        "TotalAlloc": true,
        "LastGC":     true,
    }

    res, err := http.Get("http://localhost:8080/memstats")
    if err != nil {
        log.Fatal(err)
    }
    body, err := ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        log.Fatal(err)
    }

    data := &responseMemStats{}
    if err = json.Unmarshal(body, data); err != nil {
        log.Fatal(err)
    }

    v := reflect.Indirect(reflect.ValueOf(data))
    t := v.Type()
    rows := []string{}
    for i := 0; i < t.NumField(); i++ {
        if !targetFields[t.Field(i).Name] {
            continue
        }
        f := v.Field(i)
        row := fmt.Sprintf("%s:%s", t.Field(i).Name, f.String())
        rows = append(rows, row)
    }

    fmt.Println(strings.Join(rows, ","))
}

適当に出力できます