vitess.io/vitess@v0.16.2/go/stats/statsd/statsd_test.go (about) 1 package statsd 2 3 import ( 4 "expvar" 5 "net" 6 "sort" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/DataDog/datadog-go/statsd" 12 "github.com/stretchr/testify/assert" 13 14 "vitess.io/vitess/go/stats" 15 ) 16 17 func getBackend(t *testing.T) (StatsBackend, *net.UDPConn) { 18 addr := "localhost:1201" 19 udpAddr, _ := net.ResolveUDPAddr("udp", addr) 20 server, _ := net.ListenUDP("udp", udpAddr) 21 bufferLength := 9 22 client, _ := statsd.NewBuffered(addr, bufferLength) 23 client.Namespace = "test." 24 var sb StatsBackend 25 sb.namespace = "foo" 26 sb.sampleRate = 1 27 sb.statsdClient = client 28 stats.RegisterTimerHook(func(stats, name string, value int64, timings *stats.Timings) { 29 tags := makeLabels(strings.Split(timings.Label(), "."), name) 30 client.TimeInMilliseconds(stats, float64(value), tags, sb.sampleRate) 31 }) 32 stats.RegisterHistogramHook(func(name string, val int64) { 33 client.Histogram(name, float64(val), []string{}, sb.sampleRate) 34 }) 35 return sb, server 36 } 37 38 func TestStatsdCounter(t *testing.T) { 39 sb, server := getBackend(t) 40 defer server.Close() 41 name := "counter_name" 42 c := stats.NewCounter(name, "counter description") 43 c.Add(1) 44 found := false 45 expvar.Do(func(kv expvar.KeyValue) { 46 found = true 47 if kv.Key == name { 48 sb.addExpVar(kv) 49 if err := sb.statsdClient.Flush(); err != nil { 50 t.Errorf("Error flushing: %s", err) 51 } 52 bytes := make([]byte, 4096) 53 n, err := server.Read(bytes) 54 if err != nil { 55 t.Fatal(err) 56 } 57 result := string(bytes[:n]) 58 expected := "test.counter_name:1|c\n" 59 assert.Equal(t, expected, result) 60 } 61 }) 62 if !found { 63 t.Errorf("Stat %s not found...", name) 64 } 65 } 66 67 func TestStatsdGauge(t *testing.T) { 68 sb, server := getBackend(t) 69 defer server.Close() 70 name := "gauge_name" 71 s := stats.NewGauge(name, "help") 72 s.Set(10) 73 found := false 74 expvar.Do(func(kv expvar.KeyValue) { 75 if kv.Key == name { 76 found = true 77 sb.addExpVar(kv) 78 if err := sb.statsdClient.Flush(); err != nil { 79 t.Errorf("Error flushing: %s", err) 80 } 81 bytes := make([]byte, 4096) 82 n, err := server.Read(bytes) 83 if err != nil { 84 t.Fatal(err) 85 } 86 result := string(bytes[:n]) 87 expected := "test.gauge_name:10|g\n" 88 assert.Equal(t, expected, result) 89 } 90 }) 91 if !found { 92 t.Errorf("Stat %s not found...", name) 93 } 94 } 95 96 func TestStatsdGaugeFloat64(t *testing.T) { 97 sb, server := getBackend(t) 98 defer server.Close() 99 name := "gauge_name_f64" 100 s := stats.NewGaugeFloat64(name, "help") 101 s.Set(3.14) 102 found := false 103 expvar.Do(func(kv expvar.KeyValue) { 104 if kv.Key == name { 105 found = true 106 sb.addExpVar(kv) 107 if err := sb.statsdClient.Flush(); err != nil { 108 t.Errorf("Error flushing: %s", err) 109 } 110 bytes := make([]byte, 4096) 111 n, err := server.Read(bytes) 112 if err != nil { 113 t.Fatal(err) 114 } 115 result := string(bytes[:n]) 116 expected := "test.gauge_name_f64:3.14|g\n" 117 assert.Equal(t, expected, result) 118 } 119 }) 120 if !found { 121 t.Errorf("Stat %s not found...", name) 122 } 123 } 124 125 func TestStatsdGaugeFunc(t *testing.T) { 126 sb, server := getBackend(t) 127 defer server.Close() 128 name := "gauge_func_name" 129 stats.NewGaugeFunc(name, "help", func() int64 { 130 return 2 131 }) 132 found := false 133 expvar.Do(func(kv expvar.KeyValue) { 134 if kv.Key == name { 135 found = true 136 sb.addExpVar(kv) 137 if err := sb.statsdClient.Flush(); err != nil { 138 t.Errorf("Error flushing: %s", err) 139 } 140 bytes := make([]byte, 4096) 141 n, err := server.Read(bytes) 142 if err != nil { 143 t.Fatal(err) 144 } 145 result := string(bytes[:n]) 146 expected := "test.gauge_func_name:2|g\n" 147 assert.Equal(t, expected, result) 148 } 149 }) 150 if !found { 151 t.Errorf("Stat %s not found...", name) 152 } 153 } 154 155 func TestStatsdCounterDuration(t *testing.T) { 156 sb, server := getBackend(t) 157 defer server.Close() 158 name := "counter_duration_name" 159 s := stats.NewCounterDuration(name, "help") 160 s.Add(1 * time.Millisecond) 161 found := false 162 expvar.Do(func(kv expvar.KeyValue) { 163 if kv.Key == name { 164 found = true 165 sb.addExpVar(kv) 166 if err := sb.statsdClient.Flush(); err != nil { 167 t.Errorf("Error flushing: %s", err) 168 } 169 bytes := make([]byte, 4096) 170 n, err := server.Read(bytes) 171 if err != nil { 172 t.Fatal(err) 173 } 174 result := string(bytes[:n]) 175 expected := "test.counter_duration_name:1.000000|ms\n" 176 assert.Equal(t, expected, result) 177 } 178 }) 179 if !found { 180 t.Errorf("Stat %s not found...", name) 181 } 182 } 183 184 func TestStatsdCountersWithSingleLabel(t *testing.T) { 185 sb, server := getBackend(t) 186 defer server.Close() 187 name := "counter_with_single_label_name" 188 s := stats.NewCountersWithSingleLabel(name, "help", "label", "tag1", "tag2") 189 s.Add("tag1", 2) 190 found := false 191 expvar.Do(func(kv expvar.KeyValue) { 192 if kv.Key == name { 193 found = true 194 sb.addExpVar(kv) 195 if err := sb.statsdClient.Flush(); err != nil { 196 t.Errorf("Error flushing: %s", err) 197 } 198 bytes := make([]byte, 4096) 199 n, err := server.Read(bytes) 200 if err != nil { 201 t.Fatal(err) 202 } 203 result := strings.Split(string(bytes[:n]), "\n") 204 sort.Strings(result) 205 expected := []string{ 206 "", 207 "test.counter_with_single_label_name:0|c|#label:tag2", 208 "test.counter_with_single_label_name:2|c|#label:tag1", 209 } 210 for i, res := range result { 211 assert.Equal(t, expected[i], res) 212 } 213 } 214 }) 215 if !found { 216 t.Errorf("Stat %s not found...", name) 217 } 218 } 219 220 func TestStatsdCountersWithMultiLabels(t *testing.T) { 221 sb, server := getBackend(t) 222 defer server.Close() 223 name := "counter_with_multiple_label_name" 224 s := stats.NewCountersWithMultiLabels(name, "help", []string{"label1", "label2"}) 225 s.Add([]string{"foo", "bar"}, 1) 226 found := false 227 expvar.Do(func(kv expvar.KeyValue) { 228 if kv.Key == name { 229 found = true 230 sb.addExpVar(kv) 231 if err := sb.statsdClient.Flush(); err != nil { 232 t.Errorf("Error flushing: %s", err) 233 } 234 bytes := make([]byte, 4096) 235 n, err := server.Read(bytes) 236 if err != nil { 237 t.Fatal(err) 238 } 239 result := string(bytes[:n]) 240 expected := "test.counter_with_multiple_label_name:1|c|#label1:foo,label2:bar\n" 241 assert.Equal(t, expected, result) 242 } 243 }) 244 if !found { 245 t.Errorf("Stat %s not found...", name) 246 } 247 } 248 249 func TestStatsdCountersFuncWithMultiLabels(t *testing.T) { 250 sb, server := getBackend(t) 251 defer server.Close() 252 name := "counter_func_with_multiple_labels_name" 253 stats.NewCountersFuncWithMultiLabels(name, "help", []string{"label1", "label2"}, func() map[string]int64 { 254 m := make(map[string]int64) 255 m["foo.bar"] = 1 256 m["bar.baz"] = 2 257 return m 258 }) 259 found := false 260 expvar.Do(func(kv expvar.KeyValue) { 261 if kv.Key == name { 262 found = true 263 sb.addExpVar(kv) 264 if err := sb.statsdClient.Flush(); err != nil { 265 t.Errorf("Error flushing: %s", err) 266 } 267 bytes := make([]byte, 4096) 268 n, err := server.Read(bytes) 269 if err != nil { 270 t.Fatal(err) 271 } 272 result := strings.Split(string(bytes[:n]), "\n") 273 sort.Strings(result) 274 expected := []string{ 275 "", 276 "test.counter_func_with_multiple_labels_name:1|c|#label1:foo,label2:bar", 277 "test.counter_func_with_multiple_labels_name:2|c|#label1:bar,label2:baz", 278 } 279 for i, res := range result { 280 assert.Equal(t, expected[i], res) 281 } 282 } 283 }) 284 if !found { 285 t.Errorf("Stat %s not found...", name) 286 } 287 } 288 289 func TestStatsdGaugesWithMultiLabels(t *testing.T) { 290 sb, server := getBackend(t) 291 defer server.Close() 292 name := "gauges_with_multiple_label_name" 293 s := stats.NewGaugesWithMultiLabels(name, "help", []string{"label1", "label2"}) 294 s.Add([]string{"foo", "bar"}, 3) 295 found := false 296 expvar.Do(func(kv expvar.KeyValue) { 297 if kv.Key == name { 298 found = true 299 sb.addExpVar(kv) 300 if err := sb.statsdClient.Flush(); err != nil { 301 t.Errorf("Error flushing: %s", err) 302 } 303 bytes := make([]byte, 4096) 304 n, err := server.Read(bytes) 305 if err != nil { 306 t.Fatal(err) 307 } 308 result := string(bytes[:n]) 309 expected := "test.gauges_with_multiple_label_name:3|g|#label1:foo,label2:bar\n" 310 assert.Equal(t, expected, result) 311 } 312 }) 313 if !found { 314 t.Errorf("Stat %s not found...", name) 315 } 316 } 317 318 func TestStatsdGaugesFuncWithMultiLabels(t *testing.T) { 319 sb, server := getBackend(t) 320 defer server.Close() 321 name := "gauges_func_with_multiple_labels_name" 322 stats.NewGaugesFuncWithMultiLabels(name, "help", []string{"label1", "label2"}, func() map[string]int64 { 323 m := make(map[string]int64) 324 m["foo.bar"] = 1 325 m["bar.baz"] = 2 326 return m 327 }) 328 found := false 329 expvar.Do(func(kv expvar.KeyValue) { 330 if kv.Key == name { 331 found = true 332 sb.addExpVar(kv) 333 if err := sb.statsdClient.Flush(); err != nil { 334 t.Errorf("Error flushing: %s", err) 335 } 336 bytes := make([]byte, 4096) 337 n, err := server.Read(bytes) 338 if err != nil { 339 t.Fatal(err) 340 } 341 result := strings.Split(string(bytes[:n]), "\n") 342 sort.Strings(result) 343 expected := []string{ 344 "", 345 "test.gauges_func_with_multiple_labels_name:1|g|#label1:foo,label2:bar", 346 "test.gauges_func_with_multiple_labels_name:2|g|#label1:bar,label2:baz", 347 } 348 for i, res := range result { 349 assert.Equal(t, expected[i], res) 350 } 351 } 352 }) 353 if !found { 354 t.Errorf("Stat %s not found...", name) 355 } 356 } 357 358 func TestStatsdGaugesWithSingleLabel(t *testing.T) { 359 sb, server := getBackend(t) 360 defer server.Close() 361 name := "gauges_with_single_label_name" 362 s := stats.NewGaugesWithSingleLabel(name, "help", "label1") 363 s.Add("bar", 1) 364 found := false 365 expvar.Do(func(kv expvar.KeyValue) { 366 if kv.Key == name { 367 found = true 368 sb.addExpVar(kv) 369 if err := sb.statsdClient.Flush(); err != nil { 370 t.Errorf("Error flushing: %s", err) 371 } 372 bytes := make([]byte, 4096) 373 n, err := server.Read(bytes) 374 if err != nil { 375 t.Fatal(err) 376 } 377 result := string(bytes[:n]) 378 expected := "test.gauges_with_single_label_name:1|g|#label1:bar\n" 379 assert.Equal(t, expected, result) 380 } 381 }) 382 if !found { 383 t.Errorf("Stat %s not found...", name) 384 } 385 } 386 387 func TestStatsdMultiTimings(t *testing.T) { 388 sb, server := getBackend(t) 389 defer server.Close() 390 name := "multi_timings_name" 391 s := stats.NewMultiTimings(name, "help", []string{"label1", "label2"}) 392 s.Add([]string{"foo", "bar"}, 10*time.Millisecond) 393 found := false 394 expvar.Do(func(kv expvar.KeyValue) { 395 if kv.Key == name { 396 found = true 397 sb.addExpVar(kv) 398 if err := sb.statsdClient.Flush(); err != nil { 399 t.Errorf("Error flushing: %s", err) 400 } 401 bytes := make([]byte, 49152) 402 n, err := server.Read(bytes) 403 if err != nil { 404 t.Fatal(err) 405 } 406 result := string(bytes[:n]) 407 expected := "test.multi_timings_name:10.000000|ms|#label1:foo,label2:bar\n" 408 assert.Equal(t, expected, result) 409 } 410 }) 411 if !found { 412 t.Errorf("Stat %s not found...", name) 413 } 414 } 415 416 func TestStatsdTimings(t *testing.T) { 417 sb, server := getBackend(t) 418 defer server.Close() 419 name := "timings_name" 420 s := stats.NewTimings(name, "help", "label1") 421 s.Add("foo", 2*time.Millisecond) 422 found := false 423 expvar.Do(func(kv expvar.KeyValue) { 424 if kv.Key == name { 425 found = true 426 sb.addExpVar(kv) 427 if err := sb.statsdClient.Flush(); err != nil { 428 t.Errorf("Error flushing: %s", err) 429 } 430 bytes := make([]byte, 49152) 431 n, err := server.Read(bytes) 432 if err != nil { 433 t.Fatal(err) 434 } 435 result := string(bytes[:n]) 436 expected := "test.timings_name:2.000000|ms|#label1:foo\n" 437 assert.Equal(t, expected, result) 438 } 439 }) 440 if !found { 441 t.Errorf("Stat %s not found...", name) 442 } 443 } 444 445 func TestStatsdHistogram(t *testing.T) { 446 sb, server := getBackend(t) 447 defer server.Close() 448 name := "histogram_name" 449 s := stats.NewHistogram(name, "help", []int64{1, 5, 10}) 450 s.Add(2) 451 s.Add(3) 452 s.Add(6) 453 found := false 454 expvar.Do(func(kv expvar.KeyValue) { 455 if kv.Key == name { 456 found = true 457 sb.addExpVar(kv) 458 if err := sb.statsdClient.Flush(); err != nil { 459 t.Errorf("Error flushing: %s", err) 460 } 461 bytes := make([]byte, 4096) 462 n, err := server.Read(bytes) 463 if err != nil { 464 t.Fatal(err) 465 } 466 result := string(bytes[:n]) 467 expected := []string{ 468 "test.histogram_name:2|h", 469 "test.histogram_name:3|h", 470 "test.histogram_name:6|h", 471 "", 472 } 473 for i, res := range strings.Split(result, "\n") { 474 assert.Equal(t, expected[i], res) 475 } 476 } 477 }) 478 if !found { 479 t.Errorf("Stat %s not found...", name) 480 } 481 } 482 483 func TestMakeCommonTags(t *testing.T) { 484 res1 := makeCommonTags(map[string]string{}) 485 assert.Equal(t, 0, len(res1)) 486 expected2 := []string{"a:b", "c:d"} 487 res2 := makeCommonTags(map[string]string{"a": "b", "c": "d"}) 488 assert.ElementsMatch(t, expected2, res2) 489 }