func appendDataToSpreadsheet(fileName, dir string) {
	ssRange, ok := filenameToSSRange[fileName]
	if !ok {
		log.Printf("No filename %s; cannot log to spreadsheet\n", fileName)
		return
	}
	file, err := os.Open(dir + fileName)
	if err != nil {
		log.Printf("Unable to open file: %v\n", err)
		return
	}
	r := csv.NewReader(file)
	records, err := r.ReadAll()
	if err != nil {
		log.Fatal(err)
	}
	recordsWOHeader := records[1:]
	s := make([][]interface{}, len(recordsWOHeader))
	for i, v := range recordsWOHeader {
		s[i] = make([]interface{}, len(v))
		for j, w := range v {
			s[i][j] = w
		}
	}
	srv := getSheetsClient()
	vr := sheets.ValueRange{
		MajorDimension: "ROWS",
		Values:         s,
	}
	_, err = srv.Spreadsheets.Values.Append(ssID, ssRange, &vr).ValueInputOption("RAW").Do()
	if err != nil {
		log.Fatal(err)
	}
}
appendDataToSpreadsheet inserts the CSV file in the named directory
into the spreadsheet identified using the ssID const.
package main
import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	sheets "google.golang.org/api/sheets/v4"
)
func getClient(config *oauth2.Config) *http.Client {
	tokFile := "token.json"
	tok, err := tokenFromFile(tokFile)
	if err != nil {
		tok = getTokenFromWeb(config)
		saveToken(tokFile, tok)
	}
	return config.Client(context.Background(), tok)
}
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
	fmt.Printf("Go to the following link in your browser then type the "+
		"authorization code: \n%v\n", authURL)
	var authCode string
	if _, err := fmt.Scan(&authCode); err != nil {
		log.Fatalf("Unable to read authorization code: %v", err)
	}
	tok, err := config.Exchange(context.TODO(), authCode)
	if err != nil {
		log.Fatalf("Unable to retrieve token from web: %v", err)
	}
	return tok
}
func tokenFromFile(file string) (*oauth2.Token, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	tok := &oauth2.Token{}
	err = json.NewDecoder(f).Decode(tok)
	return tok, err
}
func saveToken(path string, token *oauth2.Token) {
	fmt.Printf("Saving credential file to: %s\n", path)
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		log.Fatalf("Unable to cache oauth token: %v", err)
	}
	defer f.Close()
	json.NewEncoder(f).Encode(token)
}
func getSheetsClient() *sheets.Service {
	b, err := ioutil.ReadFile("./credentials.json")
	if err != nil {
		log.Fatalf("Unable to read client secret file; must be in same dir as binary %v", err)
	}
	config, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets")
	if err != nil {
		log.Fatalf("Unable to parse client secret file to config: %v", err)
	}
	client := getClient(config)
	srv, err := sheets.New(client)
	if err != nil {
		log.Fatalf("Unable to retrieve Sheets client: %v", err)
	}
	return srv
}
const ssID = "175Q3g3Ti40rEmaCMwm0CBXRnHIo07WSBsxOVhmqNyEY"
var filenameToSSRange = map[string]string{
	"/cpu.csv":                  "CPU!A:G",
	"/io-load-results.csv":      "'FileIO Load'!A:B",
	"/io-rd-results.csv":        "'FileIO Read'!A:I",
	"/io-wr-results.csv":        "'FileIO Write'!A:J",
	"/network-iperf-client.csv": "iperf!A:D",
	"/network-ping.csv":         "ping!A:E",
	"/run-data.csv":             "Runs!A:E",
}