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 }
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 }