vitess.io/vitess@v0.16.2/go/stats/prometheusbackend/prometheusbackend_test.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 package prometheusbackend 18 19 import ( 20 "fmt" 21 "net/http" 22 "net/http/httptest" 23 "os" 24 "strings" 25 "testing" 26 "time" 27 28 "vitess.io/vitess/go/stats" 29 30 "github.com/prometheus/client_golang/prometheus/promhttp" 31 ) 32 33 const namespace = "namespace" 34 35 func TestPrometheusCounter(t *testing.T) { 36 name := "blah" 37 c := stats.NewCounter(name, "blah") 38 c.Add(1) 39 checkHandlerForMetrics(t, name, 1) 40 //TODO: ban this? And for other counter types too? 41 // c.Add(-1) 42 c.Reset() 43 checkHandlerForMetrics(t, name, 0) 44 } 45 46 func TestPrometheusGauge(t *testing.T) { 47 name := "blah_gauge" 48 c := stats.NewGauge(name, "help") 49 c.Add(1) 50 checkHandlerForMetrics(t, name, 1) 51 c.Add(-1) 52 checkHandlerForMetrics(t, name, 0) 53 c.Set(-5) 54 checkHandlerForMetrics(t, name, -5) 55 c.Reset() 56 checkHandlerForMetrics(t, name, 0) 57 } 58 59 func TestPrometheusGaugeFloat64(t *testing.T) { 60 name := "blah_gauge_f64" 61 c := stats.NewGaugeFloat64(name, "help") 62 c.Set(3.14) 63 checkHandlerForMetrics(t, name, 3) 64 c.Reset() 65 checkHandlerForMetrics(t, name, 0) 66 } 67 68 func TestPrometheusCounterFunc(t *testing.T) { 69 name := "blah_counterfunc" 70 stats.NewCounterFunc(name, "help", func() int64 { 71 return 2 72 }) 73 74 checkHandlerForMetrics(t, name, 2) 75 } 76 77 func TestPrometheusGaugeFunc(t *testing.T) { 78 name := "blah_gaugefunc" 79 80 stats.NewGaugeFunc(name, "help", func() int64 { 81 return -3 82 }) 83 84 checkHandlerForMetrics(t, name, -3) 85 } 86 87 func TestPrometheusFloatFunc(t *testing.T) { 88 name := "blah_floatfunc" 89 90 stats.Publish(name, stats.FloatFunc(func() float64 { return -4 })) 91 checkHandlerForMetrics(t, name, -4) 92 } 93 94 func TestPrometheusCounterDuration(t *testing.T) { 95 name := "blah_counterduration" 96 97 d := stats.NewCounterDuration(name, "help") 98 d.Add(1 * time.Second) 99 100 checkHandlerForMetrics(t, name, 1) 101 } 102 103 func TestPrometheusCounterDurationFunc(t *testing.T) { 104 name := "blah_counterdurationfunc" 105 106 stats.NewCounterDurationFunc(name, "help", func() time.Duration { return 1 * time.Second }) 107 108 checkHandlerForMetrics(t, name, 1) 109 } 110 111 func TestPrometheusGaugeDuration(t *testing.T) { 112 name := "blah_gaugeduration" 113 114 d := stats.NewGaugeDuration(name, "help") 115 d.Set(1 * time.Second) 116 117 checkHandlerForMetrics(t, name, 1) 118 } 119 120 func TestPrometheusGaugeDurationFunc(t *testing.T) { 121 name := "blah_gaugedurationfunc" 122 123 stats.NewGaugeDurationFunc(name, "help", func() time.Duration { return 1 * time.Second }) 124 125 checkHandlerForMetrics(t, name, 1) 126 } 127 128 func checkHandlerForMetrics(t *testing.T, metric string, value int) { 129 response := testMetricsHandler(t) 130 131 expected := fmt.Sprintf("%s_%s %d", namespace, metric, value) 132 133 if !strings.Contains(response.Body.String(), expected) { 134 t.Fatalf("Expected %s got %s", expected, response.Body.String()) 135 } 136 } 137 138 func TestPrometheusCountersWithSingleLabel(t *testing.T) { 139 name := "blah_counterswithsinglelabel" 140 c := stats.NewCountersWithSingleLabel(name, "help", "label", "tag1", "tag2") 141 c.Add("tag1", 1) 142 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", 1) 143 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag2", 0) 144 c.Add("tag2", 41) 145 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", 1) 146 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag2", 41) 147 c.Reset("tag2") 148 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", 1) 149 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag2", 0) 150 } 151 152 func TestPrometheusGaugesWithSingleLabel(t *testing.T) { 153 name := "blah_gaugeswithsinglelabel" 154 c := stats.NewGaugesWithSingleLabel(name, "help", "label", "tag1", "tag2") 155 c.Add("tag1", 1) 156 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", 1) 157 158 c.Add("tag2", 1) 159 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag2", 1) 160 161 c.Set("tag1", -1) 162 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", -1) 163 164 c.Reset("tag2") 165 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag1", -1) 166 checkHandlerForMetricWithSingleLabel(t, name, "label", "tag2", 0) 167 } 168 169 func checkHandlerForMetricWithSingleLabel(t *testing.T, metric, label, tag string, value int) { 170 response := testMetricsHandler(t) 171 172 expected := fmt.Sprintf("%s_%s{%s=\"%s\"} %d", namespace, metric, label, tag, value) 173 174 if !strings.Contains(response.Body.String(), expected) { 175 t.Fatalf("Expected %s got %s", expected, response.Body.String()) 176 } 177 } 178 179 func TestPrometheusCountersWithMultiLabels(t *testing.T) { 180 name := "blah_counterswithmultilabels" 181 labels := []string{"label1", "label2"} 182 labelValues := []string{"foo", "bar"} 183 c := stats.NewCountersWithMultiLabels(name, "help", labels) 184 c.Add(labelValues, 1) 185 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, 1) 186 labelValues2 := []string{"baz", "bazbar"} 187 c.Add(labelValues2, 1) 188 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, 1) 189 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues2, 1) 190 c.Reset(labelValues) 191 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, 0) 192 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues2, 1) 193 } 194 195 func TestPrometheusGaugesWithMultiLabels(t *testing.T) { 196 name := "blah_gaugeswithmultilabels" 197 labels := []string{"label1", "label2"} 198 labelValues := []string{"foo", "bar"} 199 c := stats.NewGaugesWithMultiLabels(name, "help", labels) 200 c.Add(labelValues, 1) 201 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, 1) 202 203 c.Set(labelValues, -1) 204 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, -1) 205 206 labelValues2 := []string{"baz", "bazbar"} 207 c.Add(labelValues2, 1) 208 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, -1) 209 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues2, 1) 210 211 c.Reset(labelValues) 212 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues, 0) 213 checkHandlerForMetricWithMultiLabels(t, name, labels, labelValues2, 1) 214 } 215 216 func TestPrometheusCountersWithMultiLabels_AddPanic(t *testing.T) { 217 defer func() { 218 if r := recover(); r == nil { 219 t.Errorf("The code did not panic when adding to inequal label lengths") 220 } 221 }() 222 223 name := "blah_counterswithmultilabels_inequallength" 224 c := stats.NewCountersWithMultiLabels(name, "help", []string{"label1", "label2"}) 225 c.Add([]string{"label1"}, 1) 226 } 227 228 func TestPrometheusCountersFuncWithMultiLabels(t *testing.T) { 229 name := "blah_countersfuncwithmultilabels" 230 labels := []string{"label1", "label2"} 231 232 stats.NewCountersFuncWithMultiLabels(name, "help", labels, func() map[string]int64 { 233 m := make(map[string]int64) 234 m["foo.bar"] = 1 235 m["bar.baz"] = 1 236 return m 237 }) 238 239 checkHandlerForMetricWithMultiLabels(t, name, labels, []string{"foo", "bar"}, 1) 240 checkHandlerForMetricWithMultiLabels(t, name, labels, []string{"bar", "baz"}, 1) 241 } 242 243 func checkHandlerForMetricWithMultiLabels(t *testing.T, metric string, labels []string, labelValues []string, value int64) { 244 response := testMetricsHandler(t) 245 246 expected := fmt.Sprintf("%s_%s{%s=\"%s\",%s=\"%s\"} %d", namespace, metric, labels[0], labelValues[0], labels[1], labelValues[1], value) 247 248 if !strings.Contains(response.Body.String(), expected) { 249 t.Fatalf("Expected %s got %s", expected, response.Body.String()) 250 } 251 } 252 253 func TestPrometheusTimings(t *testing.T) { 254 name := "blah_timings" 255 cats := []string{"cat1", "cat2"} 256 timing := stats.NewTimings(name, "help", "category", cats...) 257 timing.Add("cat1", time.Duration(30*time.Millisecond)) 258 timing.Add("cat1", time.Duration(200*time.Millisecond)) 259 timing.Add("cat1", time.Duration(1*time.Second)) 260 261 response := testMetricsHandler(t) 262 var s []string 263 264 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.0005\"} %d", namespace, name, cats[0], 0)) 265 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.001\"} %d", namespace, name, cats[0], 0)) 266 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.005\"} %d", namespace, name, cats[0], 0)) 267 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.01\"} %d", namespace, name, cats[0], 0)) 268 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.05\"} %d", namespace, name, cats[0], 1)) 269 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.1\"} %d", namespace, name, cats[0], 1)) 270 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"0.5\"} %d", namespace, name, cats[0], 2)) 271 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"1\"} %d", namespace, name, cats[0], 3)) 272 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"5\"} %d", namespace, name, cats[0], 3)) 273 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"10\"} %d", namespace, name, cats[0], 3)) 274 s = append(s, fmt.Sprintf("%s_%s_bucket{category=\"%s\",le=\"+Inf\"} %d", namespace, name, cats[0], 3)) 275 s = append(s, fmt.Sprintf("%s_%s_sum{category=\"%s\"} %s", namespace, name, cats[0], "1.23")) 276 s = append(s, fmt.Sprintf("%s_%s_count{category=\"%s\"} %d", namespace, name, cats[0], 3)) 277 278 for _, line := range s { 279 if !strings.Contains(response.Body.String(), line) { 280 t.Fatalf("Expected result to contain %s, got %s", line, response.Body.String()) 281 } 282 } 283 } 284 285 func TestPrometheusMultiTimings(t *testing.T) { 286 name := "blah_multitimings" 287 cats := []string{"cat1", "cat2"} 288 catLabels := []string{"foo", "bar"} 289 timing := stats.NewMultiTimings(name, "help", cats) 290 timing.Add(catLabels, time.Duration(30*time.Millisecond)) 291 timing.Add(catLabels, time.Duration(200*time.Millisecond)) 292 timing.Add(catLabels, time.Duration(1*time.Second)) 293 294 response := testMetricsHandler(t) 295 var s []string 296 297 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.0005\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 0)) 298 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.001\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 0)) 299 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.005\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 0)) 300 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.01\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 0)) 301 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.05\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 1)) 302 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.1\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 1)) 303 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"0.5\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 2)) 304 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"1\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 3)) 305 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"5\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 3)) 306 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"10\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 3)) 307 s = append(s, fmt.Sprintf("%s_%s_bucket{%s=\"%s\",%s=\"%s\",le=\"+Inf\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 3)) 308 s = append(s, fmt.Sprintf("%s_%s_sum{%s=\"%s\",%s=\"%s\"} %s", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], "1.23")) 309 s = append(s, fmt.Sprintf("%s_%s_count{%s=\"%s\",%s=\"%s\"} %d", namespace, name, cats[0], catLabels[0], cats[1], catLabels[1], 3)) 310 311 for _, line := range s { 312 if !strings.Contains(response.Body.String(), line) { 313 t.Fatalf("Expected result to contain %s, got %s", line, response.Body.String()) 314 } 315 } 316 } 317 318 func TestPrometheusMultiTimings_PanicWrongLength(t *testing.T) { 319 defer func() { 320 if r := recover(); r == nil { 321 t.Errorf("The code did not panic when adding to inequal label lengths") 322 } 323 }() 324 325 c := stats.NewMultiTimings("name", "help", []string{"label1", "label2"}) 326 c.Add([]string{"label1"}, time.Duration(100000000)) 327 } 328 329 func TestPrometheusHistogram(t *testing.T) { 330 name := "blah_hist" 331 hist := stats.NewHistogram(name, "help", []int64{1, 5, 10}) 332 hist.Add(2) 333 hist.Add(3) 334 hist.Add(6) 335 336 response := testMetricsHandler(t) 337 var s []string 338 339 s = append(s, fmt.Sprintf("%s_%s_bucket{le=\"1\"} %d", namespace, name, 0)) 340 s = append(s, fmt.Sprintf("%s_%s_bucket{le=\"5\"} %d", namespace, name, 2)) 341 s = append(s, fmt.Sprintf("%s_%s_bucket{le=\"10\"} %d", namespace, name, 3)) 342 s = append(s, fmt.Sprintf("%s_%s_sum %d", namespace, name, 1)) 343 s = append(s, fmt.Sprintf("%s_%s_count %d", namespace, name, 3)) 344 345 for _, line := range s { 346 if !strings.Contains(response.Body.String(), line) { 347 t.Fatalf("Expected result to contain %s, got %s", line, response.Body.String()) 348 } 349 } 350 } 351 352 func testMetricsHandler(t *testing.T) *httptest.ResponseRecorder { 353 req, _ := http.NewRequest("GET", "/metrics", nil) 354 response := httptest.NewRecorder() 355 356 promhttp.Handler().ServeHTTP(response, req) 357 return response 358 } 359 360 func TestPrometheusLabels(t *testing.T) { 361 m1 := stats.NewCountersWithSingleLabel("ThisIsMetric1", "helpstring1", "ThisIsALabel") 362 m1.Add("labelvalue1", 420) 363 364 m2 := stats.NewCountersWithMultiLabels("ThisIsMetric2", "helpstring2", []string{"ThisIsALabel"}) 365 m2.Add([]string{"labelvalue2"}, 420) 366 367 response := testMetricsHandler(t) 368 369 expect := []string{ 370 "namespace_this_is_metric1{this_is_a_label=\"labelvalue1\"} 420", 371 "namespace_this_is_metric2{this_is_a_label=\"labelvalue2\"} 420", 372 } 373 for _, line := range expect { 374 if !strings.Contains(response.Body.String(), line) { 375 t.Fatalf("Expected result to contain %s, got %s", line, response.Body.String()) 376 } 377 } 378 } 379 380 func TestMain(m *testing.M) { 381 Init(namespace) 382 os.Exit(m.Run()) 383 }