func graphiteExtractPlotResult(plots []graphitePlot) ([]*types.PlotResult, error) { var min, max, avg, last float64 result := make([]*types.PlotResult, 0) for _, plot := range plots { plotResult := &types.PlotResult{Info: make(map[string]types.PlotValue)} for _, plotPoint := range plot.Datapoints { plotResult.Plots = append(plotResult.Plots, types.PlotValue(plotPoint[0])) } // Scan the target legend for serie name and plot min/max/avg/last info if index := strings.Index(plots[0].Target, "(min"); index > 0 { fmt.Sscanf(plot.Target[0:index], "%s ", &plotResult.Name) fmt.Sscanf(plot.Target[index:], "(min: %f) (max: %f) (avg: %f) (last: %f)", &min, &max, &avg, &last) } plotResult.Info["min"] = types.PlotValue(min) plotResult.Info["max"] = types.PlotValue(max) plotResult.Info["avg"] = types.PlotValue(avg) plotResult.Info["last"] = types.PlotValue(last) result = append(result, plotResult) } return result, nil }
func rrdParseInfo(info rrd.GraphInfo, data []*types.PlotResult) { refMap := make(map[string]*types.PlotResult) for _, entry := range data { refMap[entry.Name] = entry } for _, value := range info.Print { chunks := strings.SplitN(value, ",", 3) chunkFloat, err := strconv.ParseFloat(chunks[2], 64) if err != nil { chunkFloat = math.NaN() } if refMap[chunks[0]] == nil { plotResult := &types.PlotResult{Info: make(map[string]types.PlotValue)} data = append(data, plotResult) refMap[chunks[0]] = plotResult } refMap[chunks[0]].Info[chunks[1]] = types.PlotValue(chunkFloat) } }
// GetPlots retrieves time series data from origin based on a query and a time interval. func (connector *RRDConnector) GetPlots(query *types.PlotQuery) ([]*types.PlotResult, error) { var xport *rrd.Exporter if len(query.Group.Series) == 0 { return nil, fmt.Errorf("group has no series") } else if query.Group.Type != OperGroupTypeNone && len(query.Group.Series) == 1 { query.Group.Type = OperGroupTypeNone } result := make([]*types.PlotResult, 0) stack := make([]string, 0) graph := rrd.NewGrapher() if connector.daemon != "" { graph.SetDaemon(connector.daemon) } xport = rrd.NewExporter() if connector.daemon != "" { xport.SetDaemon(connector.daemon) } count := 0 switch query.Group.Type { case OperGroupTypeNone: for _, serie := range query.Group.Series { if serie.Metric == nil { continue } itemName := fmt.Sprintf("serie%d", count) count += 1 graph.Def( itemName+"-orig0", connector.metrics[serie.Metric.Source][serie.Metric.Name].FilePath, connector.metrics[serie.Metric.Source][serie.Metric.Name].Dataset, "AVERAGE", ) if serie.Scale != 0 { graph.CDef(itemName+"-orig1", fmt.Sprintf("%s-orig0,%g,*", itemName, serie.Scale)) } else { graph.CDef(itemName+"-orig1", itemName+"-orig0") } if query.Group.Scale != 0 { graph.CDef(itemName, fmt.Sprintf("%s-orig1,%g,*", itemName, query.Group.Scale)) } else { graph.CDef(itemName, itemName+"-orig1") } // Set graph information request rrdSetGraph(graph, itemName, query.Percentiles) // Set plots request xport.Def( itemName+"-orig0", connector.metrics[serie.Metric.Source][serie.Metric.Name].FilePath, connector.metrics[serie.Metric.Source][serie.Metric.Name].Dataset, "AVERAGE", ) if serie.Scale != 0 { xport.CDef(itemName+"-orig1", fmt.Sprintf("%s-orig0,%g,*", itemName, serie.Scale)) } else { xport.CDef(itemName+"-orig1", itemName+"-orig0") } if query.Group.Scale != 0 { xport.CDef(itemName, fmt.Sprintf("%s-orig1,%g,*", itemName, query.Group.Scale)) } else { xport.CDef(itemName, itemName+"-orig1") } xport.XportDef(itemName, itemName) } case OperGroupTypeAvg, OperGroupTypeSum: itemName := fmt.Sprintf("serie%d", count) count += 1 for index, serie := range query.Group.Series { if serie.Metric == nil { continue } serieTemp := itemName + fmt.Sprintf("-tmp%d", index) graph.Def( serieTemp+"-ori", connector.metrics[serie.Metric.Source][serie.Metric.Name].FilePath, connector.metrics[serie.Metric.Source][serie.Metric.Name].Dataset, "AVERAGE", ) graph.CDef(serieTemp, fmt.Sprintf("%s-ori,UN,0,%s-ori,IF", serieTemp, serieTemp)) xport.Def( serieTemp+"-ori", connector.metrics[serie.Metric.Source][serie.Metric.Name].FilePath, connector.metrics[serie.Metric.Source][serie.Metric.Name].Dataset, "AVERAGE", ) xport.CDef(serieTemp, fmt.Sprintf("%s-ori,UN,0,%s-ori,IF", serieTemp, serieTemp)) if len(stack) == 0 { stack = append(stack, serieTemp) } else { stack = append(stack, serieTemp, "+") } } if query.Group.Type == OperGroupTypeAvg { stack = append(stack, strconv.Itoa(len(query.Group.Series)), "/") } graph.CDef(itemName+"-orig", strings.Join(stack, ",")) if query.Group.Scale != 0 { graph.CDef(itemName, fmt.Sprintf("%s-orig,%g,*", itemName, query.Group.Scale)) } else { graph.CDef(itemName, itemName+"-orig") } // Set graph information request rrdSetGraph(graph, itemName, query.Percentiles) // Set plots request xport.CDef(itemName+"-orig", strings.Join(stack, ",")) if query.Group.Scale != 0 { xport.CDef(itemName, fmt.Sprintf("%s-orig,%g,*", itemName, query.Group.Scale)) } else { xport.CDef(itemName, itemName+"-orig") } xport.XportDef(itemName, itemName) default: return nil, fmt.Errorf("unknown operator type %d", query.Group.Type) } // Get plots data := rrd.XportResult{} data, err := xport.Xport(query.StartTime, query.EndTime, query.Step) if err != nil { return nil, err } for index, itemName := range data.Legends { plotResult := &types.PlotResult{ Name: itemName, Info: make(map[string]types.PlotValue), } for i := 0; i < data.RowCnt; i++ { plotResult.Plots = append(plotResult.Plots, types.PlotValue(data.ValueAt(index, i))) } result = append(result, plotResult) } // Parse graph information graphInfo, _, err := graph.Graph(query.StartTime, query.EndTime) if err != nil { return nil, err } rrdParseInfo(graphInfo, result) data.FreeValues() return result, nil }