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  }