package main import ( "encoding/csv" "encoding/json" "log" "net/http" "os" "path/filepath" "strconv" "time" ) type Summary struct { StartMS float64 `json:"start_ms"` EndMS float64 `json:"end_ms"` Values []float64 `json:"values"` // [max, mean+std, mean, mean-std, min] } var ( dataFile *os.File writer *csv.Writer ) func initDataFile() { _ = os.MkdirAll("data", 0755) filename := filepath.Join( "data", time.Now().Format("summary_20060102_150405.csv"), ) f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { log.Fatal(err) } dataFile = f writer = csv.NewWriter(dataFile) // header for plotting writer.Write([]string{ "start_ms", "end_ms", "max", "mean_plus_std", "mean", "mean_minus_std", "min", }) writer.Flush() } func handler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "POST only", http.StatusMethodNotAllowed) return } var s Summary if err := json.NewDecoder(r.Body).Decode(&s); err != nil { http.Error(w, "invalid JSON", http.StatusBadRequest) return } if len(s.Values) != 5 { http.Error(w, "need 5 values", http.StatusBadRequest) return } row := []string{ formatFloat(s.StartMS), formatFloat(s.EndMS), formatFloat(s.Values[0]), formatFloat(s.Values[1]), formatFloat(s.Values[2]), formatFloat(s.Values[3]), formatFloat(s.Values[4]), } writer.Write(row) writer.Flush() log.Println("Summary appended") w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) } func formatFloat(v float64) string { return strconv.FormatFloat(v, 'f', 6, 64) } func main() { initDataFile() defer dataFile.Close() http.HandleFunc("/data", handler) log.Println("Listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }