vitess.io/vitess@v0.16.2/tools/statsd.go (about)

     1  /*
     2   * Copyright 2019 The Vitess Authors.
     3  
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7  
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // statsd is a simple server for hosting test.go remote stats.
    18  package main
    19  
    20  import (
    21  	"encoding/json"
    22  	"log"
    23  	"net/http"
    24  	"os"
    25  	"strconv"
    26  	"sync"
    27  	"time"
    28  )
    29  
    30  var mu sync.Mutex
    31  
    32  const statsFileName = "stats.json"
    33  
    34  func main() {
    35  	http.HandleFunc("/travis/stats", func(w http.ResponseWriter, r *http.Request) {
    36  		if r.Method == "POST" {
    37  			test := r.FormValue("test")
    38  			result := r.FormValue("result")
    39  
    40  			if test == "" || result == "" {
    41  				return
    42  			}
    43  
    44  			switch result {
    45  			case "pass":
    46  				duration := r.FormValue("duration")
    47  				if duration == "" {
    48  					return
    49  				}
    50  				dur, err := time.ParseDuration(duration)
    51  				if err != nil {
    52  					return
    53  				}
    54  				testPassed(test, dur)
    55  			case "fail":
    56  				testFailed(test)
    57  			case "flake":
    58  				try := r.FormValue("try")
    59  				if try == "" {
    60  					return
    61  				}
    62  				i, err := strconv.ParseInt(try, 10, 64)
    63  				if err != nil {
    64  					return
    65  				}
    66  				testFlaked(test, int(i))
    67  			}
    68  
    69  			return
    70  		}
    71  
    72  		http.ServeFile(w, r, statsFileName)
    73  	})
    74  
    75  	http.ListenAndServe(":15123", nil)
    76  }
    77  
    78  type Stats struct {
    79  	TestStats map[string]TestStats
    80  }
    81  
    82  type TestStats struct {
    83  	Pass, Fail, Flake int
    84  	PassTime          time.Duration
    85  }
    86  
    87  func testPassed(name string, passTime time.Duration) {
    88  	updateTestStats(name, func(ts *TestStats) {
    89  		totalTime := int64(ts.PassTime)*int64(ts.Pass) + int64(passTime)
    90  		ts.Pass++
    91  		ts.PassTime = time.Duration(totalTime / int64(ts.Pass))
    92  	})
    93  }
    94  
    95  func testFailed(name string) {
    96  	updateTestStats(name, func(ts *TestStats) {
    97  		ts.Fail++
    98  	})
    99  }
   100  
   101  func testFlaked(name string, try int) {
   102  	updateTestStats(name, func(ts *TestStats) {
   103  		ts.Flake += try - 1
   104  	})
   105  }
   106  
   107  func updateTestStats(name string, update func(*TestStats)) {
   108  	var stats Stats
   109  
   110  	mu.Lock()
   111  	defer mu.Unlock()
   112  
   113  	data, err := os.ReadFile(statsFileName)
   114  	if err != nil {
   115  		log.Print("Can't read stats file, starting new one.")
   116  	} else {
   117  		if err := json.Unmarshal(data, &stats); err != nil {
   118  			log.Printf("Can't parse stats file: %v", err)
   119  			return
   120  		}
   121  	}
   122  
   123  	if stats.TestStats == nil {
   124  		stats.TestStats = make(map[string]TestStats)
   125  	}
   126  	ts := stats.TestStats[name]
   127  	update(&ts)
   128  	stats.TestStats[name] = ts
   129  
   130  	data, err = json.MarshalIndent(stats, "", "\t")
   131  	if err != nil {
   132  		log.Printf("Can't encode stats file: %v", err)
   133  		return
   134  	}
   135  	if err := os.WriteFile(statsFileName, data, 0644); err != nil {
   136  		log.Printf("Can't write stats file: %v", err)
   137  	}
   138  }