github.com/m3db/m3@v1.5.0/scripts/comparator/utils/compare_utilities.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package utils
    22  
    23  import (
    24  	"encoding/json"
    25  	"io/ioutil"
    26  	"net/url"
    27  	"os"
    28  	"strconv"
    29  
    30  	"go.uber.org/zap"
    31  )
    32  
    33  // InputQueries is a slice of InputQuery.
    34  type InputQueries []InputQuery
    35  
    36  // InputQuery is the JSON representation of a query to be compared.
    37  type InputQuery struct {
    38  	// QueryGroup is the general category for these queries.
    39  	QueryGroup string `json:"queryGroup"`
    40  	// Queries is the list of raw queries.
    41  	Queries []string `json:"queries"`
    42  	// Steps is the list of step sizes for these queries.
    43  	Steps []string `json:"steps"`
    44  	// Reruns is the number of times to rerun this query group.
    45  	Reruns int `json:"reruns"`
    46  }
    47  
    48  // PromQLQueryGroup is a list of constructed PromQL query groups.
    49  type PromQLQueryGroup struct {
    50  	// QueryGroup is the general category for these queries.
    51  	QueryGroup string
    52  	// Queries is a list of PromQL compatible queries.
    53  	Queries []string
    54  	// Reruns is the number of times to rerun this query group.
    55  	Reruns int
    56  }
    57  
    58  func (q InputQueries) constructPromQL(
    59  	start int64,
    60  	end int64,
    61  ) []PromQLQueryGroup {
    62  	queries := make([]PromQLQueryGroup, 0, len(q))
    63  	for _, inQuery := range q {
    64  		queries = append(queries, inQuery.constructPromQL(start, end))
    65  	}
    66  
    67  	return queries
    68  }
    69  
    70  func (q InputQuery) constructPromQL(start int64, end int64) PromQLQueryGroup {
    71  	queries := make([]string, 0, len(q.Queries)*len(q.Steps))
    72  	for _, inQuery := range q.Queries {
    73  		for _, inStep := range q.Steps {
    74  			queryRangeValues := make(url.Values)
    75  			queryRangeValues.Add("query", inQuery)
    76  			queryRangeValues.Add("step", inStep)
    77  			queryRangeValues.Add("start", strconv.Itoa(int(start)))
    78  			queryRangeValues.Add("end", strconv.Itoa(int(end)))
    79  			queryRangePath := "/api/v1/query_range?" + queryRangeValues.Encode()
    80  
    81  			queryValues := make(url.Values)
    82  			queryValues.Add("query", inQuery)
    83  			queryValues.Add("time", strconv.Itoa(int(start)))
    84  			queryPath := "/api/v1/query?" + queryValues.Encode()
    85  
    86  			queries = append(queries, queryRangePath, queryPath)
    87  		}
    88  	}
    89  
    90  	runs := 1
    91  	if q.Reruns > 1 {
    92  		runs = q.Reruns
    93  	}
    94  
    95  	return PromQLQueryGroup{
    96  		QueryGroup: q.QueryGroup,
    97  		Queries:    queries,
    98  		Reruns:     runs,
    99  	}
   100  }
   101  
   102  func parseFileToQueries(
   103  	fileName string,
   104  	log *zap.Logger,
   105  ) (InputQueries, error) {
   106  	file, err := os.Open(fileName)
   107  	if err != nil {
   108  		log.Error("could not open file", zap.Error(err))
   109  		return nil, err
   110  	}
   111  
   112  	defer file.Close()
   113  	buf, err := ioutil.ReadAll(file)
   114  	if err != nil {
   115  		log.Error("could not read file", zap.Error(err))
   116  		return nil, err
   117  	}
   118  
   119  	queries := make(InputQueries, 0, 10)
   120  	if err := json.Unmarshal(buf, &queries); err != nil {
   121  		log.Error("could not unmarshal queries", zap.Error(err))
   122  		return nil, err
   123  	}
   124  
   125  	return queries, err
   126  }
   127  
   128  // ParseFileToPromQLQueryGroup parses a JSON queries file
   129  // into PromQL query groups.
   130  func ParseFileToPromQLQueryGroup(
   131  	fileName string,
   132  	start int64,
   133  	end int64,
   134  	log *zap.Logger,
   135  ) ([]PromQLQueryGroup, error) {
   136  	queries, err := parseFileToQueries(fileName, log)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	return queries.constructPromQL(start, end), nil
   142  }