func TestReadFromCollector(t *testing.T) { logrus.SetLevel(logrus.ErrorLevel) c := make(map[string]interface{}) c["interval"] = 1 collector := collector.New("Test") collector.SetInterval(1) collector.Configure(c) var wg sync.WaitGroup wg.Add(2) collectorStatChannel := make(chan metric.CollectorEmission) go func() { defer wg.Done() collector.Channel() <- metric.New("hello") time.Sleep(time.Duration(2) * time.Second) m2 := metric.New("world") m2.AddDimension("collectorCanonicalName", "Foobar") collector.Channel() <- m2 time.Sleep(time.Duration(2) * time.Second) m2.AddDimension("collectorCanonicalName", "Foobar") collector.Channel() <- m2 close(collector.Channel()) }() collectorMetrics := map[string]uint64{} go func() { defer wg.Done() for collectorMetric := range collectorStatChannel { collectorMetrics[collectorMetric.Name] = collectorMetric.EmissionCount } }() readFromCollector(collector, []handler.Handler{}, collectorStatChannel) wg.Wait() assert.Equal(t, uint64(1), collectorMetrics["Test"]) assert.Equal(t, uint64(2), collectorMetrics["Foobar"]) }
func TestHandlerBufferSize(t *testing.T) { base := BaseHandler{} base.log = l.WithField("testing", "basehandler_flush") base.interval = 5 base.maxBufferSize = 100 base.channel = make(chan metric.Metric) base.collectorEndpoints = map[string]CollectorEnd{ "collector1": CollectorEnd{make(chan metric.Metric), 3}, } emitFunc := func(metrics []metric.Metric) bool { assert.Equal(t, 3, len(metrics)) return true } go base.run(emitFunc) base.CollectorEndpoints()["collector1"].Channel <- metric.New("testMetric") base.CollectorEndpoints()["collector1"].Channel <- metric.New("testMetric1") base.CollectorEndpoints()["collector1"].Channel <- metric.New("testMetric2") time.Sleep(1 * time.Second) assert.Equal(t, uint64(3), atomic.LoadUint64(&base.metricsSent)) assert.Equal(t, uint64(0), atomic.LoadUint64(&base.metricsDropped)) // This is just to stop goroutines that have been started before base.channel <- metric.Metric{} base.CollectorEndpoints()["collector1"].Channel <- metric.Metric{} }
func TestKairosServerErrorParse(t *testing.T) { k := getTestKairosHandler(12, 13, 14) metrics := make([]metric.Metric, 0, 3) metrics = append(metrics, metric.New("Test1")) metrics = append(metrics, metric.New("Test2")) metrics = append(metrics, metric.New("test3")) metrics[0].AddDimension("somedim", "") metrics[1].AddDimension("somedim", "working") metrics[2].AddDimension("somedime", "") series := make([]KairosMetric, 0, len(metrics)) for i := range metrics { series = append(series, k.convertToKairos(metrics[i])) } expectMetrics := make([]KairosMetric, 0, 2) expectMetrics = append(expectMetrics, k.convertToKairos(metrics[0])) expectMetrics = append(expectMetrics, k.convertToKairos(metrics[2])) expectByt, _ := json.Marshal(expectMetrics) errByt := []byte(`{\"errors\":[\"metric[0](name=Test1).tag[somedim].value may not be empty.\",` + `\"metric[2](name=Test3).tag[somedim].value may not be empty.\"]}`) assert.Equal(t, k.parseServerError(string(errByt), series), string(expectByt)) }
func TestSignalFxSanitation(t *testing.T) { s := getTestSignalfxHandler(12, 12, 12) m1 := metric.New(" Test= .me$tric ") m1.AddDimension("simple string", "simple string") m1.AddDimension("dot.string", "dot.string") m1.AddDimension("3.3", "3.3") m1.AddDimension("slash/string", "slash/string") m1.AddDimension("colon:string", "colon:string") m1.AddDimension("equal=string", "equal=string") datapoint1 := s.convertToProto(m1) m2 := metric.New("Test-_.metric") m2.AddDimension("simple_string", "simple_string") m2.AddDimension("dot_string", "dot.string") m2.AddDimension("3_3", "3.3") m2.AddDimension("slash_string", "slash/string") m2.AddDimension("colon-string", "colon-string") m2.AddDimension("equal-string", "equal-string") datapoint2 := s.convertToProto(m2) assert.Equal(t, datapoint1.GetMetric(), datapoint2.GetMetric(), "the two metrics should be the same") for i := 0; i < len(datapoint1.GetDimensions())-1; i++ { for j := i + 1; j < len(datapoint1.GetDimensions()); j++ { assert.NotEqual(t, datapoint1.GetDimensions()[i].GetKey(), datapoint1.GetDimensions()[j].GetKey(), "the two dimensions should be different") } } }
func TestCollectorBlacklist(t *testing.T) { logrus.SetLevel(logrus.ErrorLevel) c := make(map[string]interface{}) c["interval"] = 1 c["metrics_blacklist"] = []string{"m[0-9]+$"} col := collector.New("Test") col.SetInterval(1) col.Configure(c) var wg sync.WaitGroup wg.Add(2) collectorStatChannel := make(chan metric.CollectorEmission) go func() { defer wg.Done() col.Channel() <- metric.New("m1") time.Sleep(time.Duration(2) * time.Second) col.Channel() <- metric.New("m2") time.Sleep(time.Duration(2) * time.Second) col.Channel() <- metric.New("metric3") close(col.Channel()) }() collectorMetrics := map[string]uint64{} go func() { defer wg.Done() for collectorMetric := range collectorStatChannel { collectorMetrics[collectorMetric.Name] = collectorMetric.EmissionCount } }() readFromCollector(col, []handler.Handler{}, collectorStatChannel) wg.Wait() assert.Equal(t, uint64(1), collectorMetrics["Test"]) }
func TestSanitizeMetricDimensionValue(t *testing.T) { k := getTestKairosHandler(12, 13, 14) m1 := metric.New("Test") m1.AddDimension("some=dim", "valu=") s1 := k.convertToKairos(m1) m2 := metric.New("Test") m2.AddDimension("some-dim", "valu-") s2 := k.convertToKairos(m2) assert.Equal(t, s1, s2, "metric dimension should be sanitazed") }
func TestSanitizeMetricName(t *testing.T) { k := getTestKairosHandler(12, 13, 14) m1 := metric.New("Test==:") m1.AddDimension("somedim", "value") s1 := k.convertToKairos(m1) m2 := metric.New("Test---") m2.AddDimension("somedim", "value") s2 := k.convertToKairos(m2) assert.Equal(t, s1, s2, "metric name should be sanitazed") }
func TestAddDimensions(t *testing.T) { m1 := metric.New("TestMetric") m2 := metric.New("TestMetric") dimensions := map[string]string{ "TestDimension": "TestValue", "Dirty:=Dimension": "Dirty:=Value", } m1.AddDimension("TestDimension", "TestValue") m1.AddDimension("Dirty:=Dimension", "Dirty:=Value") m2.AddDimensions(dimensions) assert.Equal(t, m1, m2) }
func procStatusPoint(name string, value float64, dimensions map[string]string) (m metric.Metric) { m = metric.New(name) m.Value = value m.AddDimension("collector", "ProcStatus") m.AddDimensions(dimensions) return m }
func TestEmissionAndRecord(t *testing.T) { emitCalled := false callbackChannel := make(chan emissionTiming) emitFunc := func([]metric.Metric) bool { emitCalled = true return true } metrics := []metric.Metric{metric.New("example")} base := BaseHandler{} base.log = l.WithField("testing", "basehandler") go base.emitAndTime(metrics, emitFunc, callbackChannel) select { case timing := <-callbackChannel: assert.NotNil(t, timing) assert.Equal(t, 1, timing.metricsSent) assert.NotNil(t, timing.timestamp) assert.NotNil(t, timing.duration) case <-time.After(2 * time.Second): t.Fatal("Failed to read from the callback channel after 2 seconds") } assert.True(t, emitCalled) callbackChannel = nil }
func TestHandlerRun(t *testing.T) { base := BaseHandler{} base.log = l.WithField("testing", "basehandler") base.interval = 1 base.maxBufferSize = 1 base.channel = make(chan metric.Metric) emitCalled := false emitFunc := func(metrics []metric.Metric) bool { assert.Equal(t, 1, len(metrics)) emitCalled = true return true } // now we are waiting for some metrics go base.run(emitFunc) base.channel <- metric.New("testMetric") time.Sleep(1 * time.Second) assert.True(t, emitCalled) assert.Equal(t, 1, base.emissionTimes.Len()) assert.Equal(t, uint64(1), base.metricsSent) assert.Equal(t, uint64(0), base.metricsDropped) assert.Equal(t, uint64(1), base.totalEmissions) assertEmpty(t, base.channel) base.channel = nil }
func TestCollectorPrefix(t *testing.T) { logrus.SetLevel(logrus.ErrorLevel) c := make(map[string]interface{}) c["interval"] = 1 c["prefix"] = "px." collector := collector.New("Test") collector.SetInterval(1) collector.Configure(c) collectorChannel := map[string]chan metric.Metric{ "Test": make(chan metric.Metric), } testHandler := handler.New("Log") testHandler.SetCollectorChannels(collectorChannel) var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() collector.Channel() <- metric.New("hello") close(collector.Channel()) }() go func() { defer wg.Done() testMetric := <-collectorChannel["Test"] assert.Equal(t, "px.hello", testMetric.Name) }() readFromCollector(collector, []handler.Handler{testHandler}) wg.Wait() }
func TestWorkingGenericHTTP(t *testing.T) { // setup the server expectedResponse := "This should come back to me" server := buildServer(expectedResponse) defer server.Close() col := buildBaseHTTPCollector(server.URL) col.errHandler = func(err error) { testLog.Error("Should not have caused an error") t.FailNow() } col.rspHandler = func(rsp *http.Response) []metric.Metric { txt, _ := ioutil.ReadAll(rsp.Body) rsp.Body.Close() assert.Equal(t, expectedResponse, string(txt)) return []metric.Metric{metric.New("junk")} } go col.Collect() m := <-col.Channel() assert.NotNil(t, m, "should have produced a single metric") assert.True(t, ensureEmpty(col.Channel()), "There should have only been a single metric") }
func reportCollector(collector collector.Collector) { log.Warn(fmt.Sprintf("%s collector took too long to run, reporting incident!", collector.Name())) metric := metric.New("fullerite.collection_time_exceeded") metric.Value = 1 metric.AddDimension("interval", fmt.Sprintf("%d", collector.Interval())) collector.Channel() <- metric }
func TestSanitizeDimensionNameOverwriteCleanDirty(t *testing.T) { defaultDimensions := make(map[string]string) m := metric.New("TestMetric") m.AddDimension("Test-Dimension", "first value") m.AddDimension("Test=Dimension", "second value") assert := assert.New(t) value, ok := m.Dimensions["Test-Dimension"] assert.Equal("second value", value, "dimension value does not match") assert.True(ok) value, ok = m.Dimensions["Test=Dimension"] assert.False(ok) value, ok = m.GetDimensionValue("Test=Dimension") assert.Equal("second value", value, "dimension value does not match") assert.True(ok) value, ok = m.GetDimensionValue("Test-Dimension") assert.Equal("second value", value, "dimension value does not match") assert.True(ok) dimensions := m.GetDimensions(defaultDimensions) value, ok = dimensions["Test-Dimension"] assert.Equal("second value", value, "dimension value does not match") assert.True(ok) value, ok = dimensions["Test=Dimension"] assert.False(ok) assert.Equal(1, len(dimensions), "only 1 dimension should exist") }
func TestSanitizeDimensionNameColon(t *testing.T) { defaultDimensions := make(map[string]string) m := metric.New("TestMetric") m.AddDimension("DirtyDimension:", "dimension value") assert := assert.New(t) value, ok := m.Dimensions["DirtyDimension-"] assert.Equal("dimension value", value, "dimension value does not match") assert.True(ok) value, ok = m.Dimensions["DirtyDimension:"] assert.False(ok) value, ok = m.GetDimensionValue("DirtyDimension:") assert.Equal("dimension value", value, "dimension value does not match") assert.True(ok) value, ok = m.GetDimensionValue("DirtyDimension-") assert.Equal("dimension value", value, "dimension value does not match") assert.True(ok) dimensions := m.GetDimensions(defaultDimensions) value, ok = dimensions["DirtyDimension:"] assert.False(ok) value, ok = dimensions["DirtyDimension-"] assert.Equal("dimension value", value, "dimension value does not match") assert.True(ok) }
// Collect produces some random test metrics. func (t Test) Collect() { metric := metric.New(t.metricName) metric.Value = rand.Float64() metric.AddDimension("testing", "yes") t.Channel() <- metric t.log.Debug(metric) }
func procStatusPoint(name string, value float64, dimensions map[string]string, metricType string) (m metric.Metric) { m = metric.New(name) m.Value = value m.AddDimensions(dimensions) m.MetricType = metricType return m }
func TestHandlerRun(t *testing.T) { var mu sync.Mutex base := BaseHandler{} base.log = l.WithField("testing", "basehandler_run") base.interval = 1 base.maxBufferSize = 1 base.channel = make(chan metric.Metric) emitCalled := false emitFunc := func(metrics []metric.Metric) bool { assert.Equal(t, 1, len(metrics)) mu.Lock() defer mu.Unlock() emitCalled = true return true } // now we are waiting for some metrics go base.run(emitFunc) base.channel <- metric.New("testMetric") time.Sleep(1 * time.Second) mu.Lock() assert.True(t, emitCalled) mu.Unlock() assert.Equal(t, 1, base.GetEmissionTimesLen()) assert.Equal(t, uint64(1), atomic.LoadUint64(&base.metricsSent)) assert.Equal(t, uint64(0), atomic.LoadUint64(&base.metricsDropped)) assert.Equal(t, uint64(1), atomic.LoadUint64(&base.totalEmissions)) base.channel <- metric.Metric{} }
func emitTestMetric(conn net.Conn) { var metrics []metric.Metric metrics = append(metrics, metric.New("test")) b, _ := json.Marshal(metrics) fmt.Fprintf(conn, string(b)+"\n") fmt.Fprintf(conn, string(b)+"\n") }
func TestGetDimensionValueNotFound(t *testing.T) { m := metric.New("TestMetric") value, ok := m.GetDimensionValue("TestDimension") assert := assert.New(t) assert.Equal(value, "", "non-existing value should be empty") assert.Equal(ok, false, "should return false") }
// Collect produces some random test metrics. func (t Test) Collect() { metric := metric.New(t.metricName) metric.Value = t.generator() metric.AddDimension("testing", "yes") time.Sleep(3 * time.Second) t.Channel() <- metric t.log.Debug(metric) }
func TestAddDimension(t *testing.T) { m := metric.New("TestMetric") m.AddDimension("TestDimension", "test value") assert := assert.New(t) assert.Equal(len(m.Dimensions), 1, "should have 1 dimension") assert.Equal(m.Dimensions["TestDimension"], "test value") }
// buildMetric creates the metric and set the correct metricType func (m *MesosSlaveStats) buildMetric(name string, value float64) metric.Metric { s := metric.New("mesos." + name) s.Value = value if _, exists := mesosSlaveCumulativeCountersList[name]; exists { s.MetricType = metric.CumulativeCounter } return s }
func TestGetDimensionValueFound(t *testing.T) { m := metric.New("TestMetric") m.AddDimension("TestDimension", "test value") value, ok := m.GetDimensionValue("TestDimension") assert := assert.New(t) assert.Equal(value, "test value", "test value does not match") assert.Equal(ok, true, "should succeed") }
func TestGetDimensionsWithDimensions(t *testing.T) { defaultDimensions := make(map[string]string) defaultDimensions["DefaultDim"] = "default value" m := metric.New("TestMetric") m.AddDimension("TestDimension", "test value") numDimensions := len(m.GetDimensions(defaultDimensions)) assert.Equal(t, numDimensions, 2, "dimensions length should be 2") }
func TestNewMetric(t *testing.T) { m := metric.New("TestMetric") assert := assert.New(t) assert.Equal(m.Name, "TestMetric") assert.Equal(m.Value, 0.0, "default value should be 0.0") assert.Equal(m.MetricType, "gauge", "should be a Gauge metric") assert.NotEqual(len(m.Dimensions), 1, "should have one dimension") }
func (hook *LogErrorHook) reportErrors(entry *logrus.Entry) { metric := metric.New("fullerite.collector_errors") metric.Value = 1 if val, exists := entry.Data["collector"]; exists { metric.AddDimension("collector", val.(string)) } hook.metricsChannel <- metric return }
func TestKairosDimensionsOverwriting(t *testing.T) { s := getTestKairosHandler(12, 12, 12) m1 := metric.New("Test") m1.AddDimension("some=dim", "first value") m1.AddDimension("some-dim", "second value") datapoint := s.convertToKairos(m1) assert.Equal(t, len(datapoint.Tags), 1, "the two metrics should be the same") }
// buildMetric Build a fullerite metric. func buildMetric(k string, v float64) metric.Metric { m := metric.New("mesos." + k) m.Value = v if _, exists := mesosMasterCumulativeCountersList[k]; exists { m.MetricType = metric.CumulativeCounter } return m }