Example #1
0
func ClassifyMetric(metric string, graphiteConverter util.RuleBasedGraphiteConverter) ConversionStatus {
	graphiteMetric := util.GraphiteMetric(metric)
	taggedMetric, err := graphiteConverter.ToTaggedName(graphiteMetric)
	if err != nil {
		return Unmatched
	}
	reversedMetric, err := graphiteConverter.ToGraphiteName(taggedMetric)
	if err != nil {
		return ReverseFailed
	}
	if reversedMetric != graphiteMetric {
		return ReverseChanged
	}
	return Matched
}
Example #2
0
func DoAnalysis(metrics []string, graphiteConverter util.RuleBasedGraphiteConverter) map[ConversionStatus][]string {
	graphiteConverter.EnableStats()

	workQueue := make(chan string, 100)

	go func() {
		// Add the metrics to the work queue
		for _, metric := range metrics {
			workQueue <- metric
		}
		close(workQueue)
	}()

	classifiedMetricResults := map[ConversionStatus]chan string{
		Matched:        make(chan string, 100),
		Unmatched:      make(chan string, 100),
		ReverseFailed:  make(chan string, 100),
		ReverseChanged: make(chan string, 100),
	}

	classifiedMetrics := map[ConversionStatus][]string{}

	var wgClassifyAppend sync.WaitGroup

	for status := range classifiedMetricResults {
		status := status
		// These goroutines move things from the `classifiedMetricResults` map (ConversionStatus => chan string)
		// into the `classifiedMetrics` map (ConversionStatus => []string)
		wgClassifyAppend.Add(1)
		go func() {
			for metric := range classifiedMetricResults[status] {
				classifiedMetrics[status] = append(classifiedMetrics[status], metric)
			}
			wgClassifyAppend.Done()
		}()
	}

	var wgWorkQueue sync.WaitGroup

	fmt.Printf("Starting work...\n")
	for i := 0; i < runtime.NumCPU(); i++ {
		// Launch 1 goroutine per CPU to process the work queue
		// This task is CPU-bound, so adding more goroutines beyond this probably won't help.
		// Benchmarking seems to confirm this suspicion- although even NumCPU() seems high
		wgWorkQueue.Add(1)
		go func() {
			counter := 0
			defer wgWorkQueue.Done()
			for metric := range workQueue {
				counter++
				if counter%1000 == 0 && counter != 0 {
					fmt.Printf(".")
				}
				// Classify the metric, then send it to the corresponding channel.
				classifiedMetricResults[ClassifyMetric(metric, graphiteConverter)] <- metric
			}
		}()
	}
	wgWorkQueue.Wait()

	for _, channel := range classifiedMetricResults {
		close(channel)
	}
	// Wait for the results to be moved from the channels into the slices.
	wgClassifyAppend.Wait()

	fmt.Printf("\n")
	fmt.Printf("Matched: %d\n", len(classifiedMetrics[Matched]))
	fmt.Printf("Unmatched: %d\n", len(classifiedMetrics[Unmatched]))
	fmt.Printf("Reverse convert failed: %d\n", len(classifiedMetrics[ReverseFailed]))
	// Since these indicate broken rules, printing out the particular metrics is very helpful.
	for _, metric := range classifiedMetrics[ReverseFailed] {
		fmt.Printf("\t%s\n", metric)
	}
	fmt.Printf("Reverse convert changed metric: %d\n", len(classifiedMetrics[ReverseChanged]))
	// Since these indicate broken rules, printing out the particular metrics is very helpful.
	for _, metric := range classifiedMetrics[ReverseChanged] {
		fmt.Printf("\t%s\n", metric)
	}
	return classifiedMetrics
}