github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/boskos/metrics/metrics.go (about) 1 /* 2 Copyright 2017 The Kubernetes 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 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "time" 24 25 "github.com/prometheus/client_golang/prometheus" 26 "github.com/prometheus/client_golang/prometheus/promhttp" 27 "github.com/sirupsen/logrus" 28 "k8s.io/test-infra/boskos/client" 29 ) 30 31 type prometheusMetrics struct { 32 GceStats map[string]prometheus.Gauge 33 GkeStats map[string]prometheus.Gauge 34 } 35 36 var ( 37 promMetrics = prometheusMetrics{ 38 GceStats: map[string]prometheus.Gauge{ 39 "free": prometheus.NewGauge(prometheus.GaugeOpts{ 40 Name: "boskos_gce_project_free", 41 Help: "Number of free gce-project", 42 }), 43 "busy": prometheus.NewGauge(prometheus.GaugeOpts{ 44 Name: "boskos_gce_project_busy", 45 Help: "Number of busy gce-project", 46 }), 47 "dirty": prometheus.NewGauge(prometheus.GaugeOpts{ 48 Name: "boskos_gce_project_dirty", 49 Help: "Number of dirty gce-project", 50 }), 51 "cleaning": prometheus.NewGauge(prometheus.GaugeOpts{ 52 Name: "boskos_gce_project_cleaning", 53 Help: "Number of cleaning gce-project", 54 }), 55 }, 56 GkeStats: map[string]prometheus.Gauge{ 57 "free": prometheus.NewGauge(prometheus.GaugeOpts{ 58 Name: "boskos_gke_project_free", 59 Help: "Number of free gke-project", 60 }), 61 "busy": prometheus.NewGauge(prometheus.GaugeOpts{ 62 Name: "boskos_gke_project_busy", 63 Help: "Number of busy gke-project", 64 }), 65 "dirty": prometheus.NewGauge(prometheus.GaugeOpts{ 66 Name: "boskos_gke_project_dirty", 67 Help: "Number of dirty gke-project", 68 }), 69 "cleaning": prometheus.NewGauge(prometheus.GaugeOpts{ 70 Name: "boskos_gke_project_cleaning", 71 Help: "Number of cleaning gke-project", 72 }), 73 }, 74 } 75 ) 76 77 func init() { 78 for _, gce := range promMetrics.GceStats { 79 prometheus.MustRegister(gce) 80 } 81 82 for _, gke := range promMetrics.GkeStats { 83 prometheus.MustRegister(gke) 84 } 85 } 86 87 func main() { 88 logrus.SetFormatter(&logrus.JSONFormatter{}) 89 boskos := client.NewClient("Metrics", "http://boskos") 90 logrus.Infof("Initialzied boskos client!") 91 92 http.Handle("/prometheus", promhttp.Handler()) 93 http.Handle("/", handleMetric(boskos)) 94 95 go func() { 96 logTick := time.NewTicker(time.Minute).C 97 for { 98 select { 99 case <-logTick: 100 if err := update(boskos); err != nil { 101 logrus.WithError(err).Warning("[Boskos Metrics]Update failed!") 102 } 103 } 104 } 105 }() 106 107 logrus.Info("Start Service") 108 logrus.WithError(http.ListenAndServe(":8080", nil)).Fatal("ListenAndServe returned.") 109 } 110 111 func update(boskos *client.Client) error { 112 gce, err := boskos.Metric("gce-project") 113 if err != nil { 114 return fmt.Errorf("fail to get metric for gce-project : %v", err) 115 } 116 117 promMetrics.GceStats["free"].Set(float64(gce.Current["free"])) 118 promMetrics.GceStats["busy"].Set(float64(gce.Current["busy"])) 119 promMetrics.GceStats["dirty"].Set(float64(gce.Current["dirty"])) 120 promMetrics.GceStats["cleaning"].Set(float64(gce.Current["cleaning"])) 121 122 gke, err := boskos.Metric("gke-project") 123 if err != nil { 124 return fmt.Errorf("fail to get metric for gke-project : %v", err) 125 } 126 127 promMetrics.GkeStats["free"].Set(float64(gke.Current["free"])) 128 promMetrics.GkeStats["busy"].Set(float64(gke.Current["busy"])) 129 promMetrics.GkeStats["dirty"].Set(float64(gke.Current["dirty"])) 130 promMetrics.GkeStats["cleaning"].Set(float64(gke.Current["cleaning"])) 131 132 return nil 133 } 134 135 // handleMetric: Handler for / 136 // Method: GET 137 func handleMetric(boskos *client.Client) http.HandlerFunc { 138 return func(res http.ResponseWriter, req *http.Request) { 139 log := logrus.WithField("handler", "handleMetric") 140 log.Infof("From %v", req.RemoteAddr) 141 142 if req.Method != "GET" { 143 log.Warning("[BadRequest]method %v, expect GET", req.Method) 144 http.Error(res, "only accepts GET request", http.StatusMethodNotAllowed) 145 return 146 } 147 148 rtype := req.URL.Query().Get("type") 149 if rtype == "" { 150 msg := "type must be set in the request." 151 log.Warning(msg) 152 http.Error(res, msg, http.StatusBadRequest) 153 return 154 } 155 156 log.Infof("Request for metric %v", rtype) 157 158 metric, err := boskos.Metric(rtype) 159 if err != nil { 160 log.WithError(err).Errorf("Fail to get metic for %v", rtype) 161 http.Error(res, err.Error(), http.StatusNotFound) 162 return 163 } 164 165 metricJSON, err := json.Marshal(metric) 166 if err != nil { 167 log.WithError(err).Errorf("json.Marshal failed: %v", metricJSON) 168 http.Error(res, err.Error(), http.StatusInternalServerError) 169 return 170 } 171 log.Infof("Metric query for %v: %v", rtype, string(metricJSON)) 172 fmt.Fprint(res, string(metricJSON)) 173 } 174 }