Example #1
0
// GetPlots retrieves time series data from origin based on a query and a time interval.
func (c *FacetteConnector) GetPlots(query *plot.Query) ([]*plot.Series, error) {
	var results []*plot.Series

	// Convert plotQuery into plotRequest-like to forward query to upstream Facette API
	plotReq := facettePlotRequest{
		Time:   query.StartTime,
		Range:  utils.DurationToRange(query.EndTime.Sub(query.StartTime)),
		Sample: query.Sample,
		Graph: library.Graph{
			Item: library.Item{
				Name: "facette",
			},
			Groups: []*library.OperGroup{
				&library.OperGroup{
					Name: "group0",
					Series: func(series []plot.QuerySeries) []*library.Series {
						out := make([]*library.Series, len(series))

						for i, s := range series {
							out[i] = &library.Series{
								Name:   fmt.Sprintf("series%d", i),
								Origin: s.Origin,
								Source: s.Source,
								Metric: s.Metric,
							}
						}

						return out
					}(query.Series),
				},
			},
		},
	}

	body, err := json.Marshal(plotReq)
	if err != nil {
		return nil, fmt.Errorf("facette[%s]: unable to marshal plot request: %s", c.name, err)
	}

	client := utils.NewHTTPClient(c.timeout, c.insecureTLS)

	r, err := http.NewRequest("POST", strings.TrimSuffix(c.upstream, "/")+facetteURLPlots, bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("facette[%s]: unable to set up HTTP request: %s", c.name, err)
	}

	r.Header.Add("Content-Type", "application/json")
	r.Header.Add("User-Agent", "Facette")
	r.Header.Add("X-Requested-With", "FacetteConnector")

	if query.Requestor != "" {
		r.Header.Add("X-Facette-Requestor", query.Requestor)
	} else {
		r.Header.Add("X-Facette-Requestor", c.serverID)
	}

	rsp, err := client.Do(r)
	if err != nil {
		return nil, fmt.Errorf("facette[%s]: unable to perform HTTP request: %s", c.name, err)
	}

	if err := facetteCheckConnectorResponse(rsp); err != nil {
		return nil, fmt.Errorf("facette[%s]: invalid upstream HTTP response: %s", c.name, err)
	}

	data, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return nil, fmt.Errorf("facette[%s]: unable to read HTTP response body: %s", c.name, err)
	}
	defer rsp.Body.Close()

	plotRsp := facettePlotResponse{}

	if err := json.Unmarshal(data, &plotRsp); err != nil {
		return nil, fmt.Errorf("facette[%s]: unable to unmarshal upstream response: %s", c.name, err)
	}

	for _, s := range plotRsp.Series {
		results = append(results, &plot.Series{
			Plots:   s.Plots,
			Summary: s.Summary,
		})
	}

	return results, nil
}
Example #2
0
// GetPlots retrieves time series data from origin based on a query and a time interval.
func (connector *FacetteConnector) GetPlots(query *types.PlotQuery) ([]*types.PlotResult, error) {
	// Convert plotQuery into plotRequest-like to forward query to upstream Facette API
	plotRequest := facettePlotRequest{
		Time:  query.StartTime,
		Range: utils.DurationToRange(query.EndTime.Sub(query.StartTime)),
		Graph: library.Graph{
			Item: library.Item{
				Name: "facette",
			},
			Groups: []*library.OperGroup{
				&library.OperGroup{
					Name: "group0",
					Type: query.Group.Type,
					Series: func(series []*types.SerieQuery) []*library.Serie {
						requestSeries := make([]*library.Serie, len(series))

						for index, serie := range series {
							requestSeries[index] = &library.Serie{
								Name:   fmt.Sprintf("serie%d", index),
								Origin: serie.Metric.Origin,
								Source: serie.Metric.Source,
								Metric: serie.Metric.Name,
								Scale:  serie.Scale,
							}
						}

						return requestSeries
					}(query.Group.Series),
					Scale: query.Group.Scale,
				},
			},
		},
	}

	if query.Step != 0 {
		plotRequest.Sample = int((query.EndTime.Sub(query.StartTime) / query.Step).Seconds())
	}

	requestBody, err := json.Marshal(plotRequest)
	if err != nil {
		return nil, fmt.Errorf("unable to marshal plot request: %s", err)
	}

	httpTransport := &http.Transport{
		Dial: (&net.Dialer{
			// Enable dual IPv4/IPv6 stack connectivity:
			DualStack: true,
			// Enforce HTTP connection timeout:
			Timeout: time.Duration(connector.timeout) * time.Second,
		}).Dial,
	}

	httpClient := http.Client{Transport: httpTransport}

	request, err := http.NewRequest(
		"POST",
		strings.TrimSuffix(connector.upstream, "/")+facetteURLLibraryGraphsPlots,
		bytes.NewReader(requestBody))
	if err != nil {
		return nil, fmt.Errorf("unable to set up HTTP request: %s", err)
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("User-Agent", "Facette")
	request.Header.Add("X-Requested-With", "FacetteConnector")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, fmt.Errorf("unable to perform HTTP request: %s", err)
	}

	if err := facetteCheckConnectorResponse(response); err != nil {
		return nil, fmt.Errorf("invalid upstream HTTP response: %s", err)
	}

	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, fmt.Errorf("unable to read HTTP response body: %s", err)
	}

	plotResponse := facettePlotResponse{}

	if err := json.Unmarshal(data, &plotResponse); err != nil {
		return nil, fmt.Errorf("unable to unmarshal upstream response: %s", err)
	}

	result := make([]*types.PlotResult, 0)

	for _, serie := range plotResponse.Series {
		result = append(result, &types.PlotResult{
			Plots: serie.Plots,
			Info:  serie.Info,
		})
	}

	return result, nil
}