added APIs for external calls

This commit is contained in:
Ankit Nayan 2021-04-26 21:55:11 +05:30
parent 381fcd710e
commit 44304229cb
4 changed files with 205 additions and 0 deletions

BIN
pkg/query-service/__debug_bin Executable file

Binary file not shown.

View File

@ -63,6 +63,9 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/services", aH.getServices).Methods(http.MethodGet)
router.HandleFunc("/api/v1/services/list", aH.getServicesList).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/overview", aH.getServiceOverview).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/externalAvgDuration", aH.GetServiceExternalAvgDuration).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/externalErrors", aH.getServiceExternalErrors).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/external", aH.getServiceExternal).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/{service}/operations", aH.getOperations).Methods(http.MethodGet)
router.HandleFunc("/api/v1/service/top_endpoints", aH.getTopEndpoints).Methods(http.MethodGet)
router.HandleFunc("/api/v1/spans", aH.searchSpans).Methods(http.MethodGet)
@ -175,6 +178,54 @@ func (aH *APIHandler) getUsage(w http.ResponseWriter, r *http.Request) {
}
func (aH *APIHandler) getServiceExternal(w http.ResponseWriter, r *http.Request) {
query, err := parseGetServiceExternalRequest(r)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
result, err := druidQuery.GetServiceExternal(aH.sqlClient, query)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) GetServiceExternalAvgDuration(w http.ResponseWriter, r *http.Request) {
query, err := parseGetServiceExternalRequest(r)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
result, err := druidQuery.GetServiceExternalAvgDuration(aH.sqlClient, query)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) getServiceExternalErrors(w http.ResponseWriter, r *http.Request) {
query, err := parseGetServiceExternalRequest(r)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
result, err := druidQuery.GetServiceExternalErrors(aH.sqlClient, query)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) getServiceOverview(w http.ResponseWriter, r *http.Request) {
query, err := parseGetServiceOverviewRequest(r)

View File

@ -76,6 +76,42 @@ func parseGetUsageRequest(r *http.Request) (*model.GetUsageParams, error) {
}
func parseGetServiceExternalRequest(r *http.Request) (*model.GetServiceOverviewParams, error) {
startTime, err := parseTime("start", r)
if err != nil {
return nil, err
}
endTime, err := parseTime("end", r)
if err != nil {
return nil, err
}
stepStr := r.URL.Query().Get("step")
if len(stepStr) == 0 {
return nil, errors.New("step param missing in query")
}
stepInt, err := strconv.Atoi(stepStr)
if err != nil {
return nil, errors.New("step param is not in correct format")
}
serviceName := r.URL.Query().Get("service")
if len(serviceName) == 0 {
return nil, errors.New("serviceName param missing in query")
}
getServiceOverviewParams := model.GetServiceOverviewParams{
StartTime: startTime.Format(time.RFC3339Nano),
EndTime: endTime.Format(time.RFC3339Nano),
ServiceName: serviceName,
Period: fmt.Sprintf("PT%dM", stepInt/60),
StepSeconds: stepInt,
}
return &getServiceOverviewParams, nil
}
func parseGetServiceOverviewRequest(r *http.Request) (*model.GetServiceOverviewParams, error) {
startTime, err := parseTime("start", r)
if err != nil {

View File

@ -32,6 +32,15 @@ type ServiceOverviewItem struct {
ErrorRate float32 `json:"errorRate"`
}
type ServiceExternalItem struct {
Time string `json:"time,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
ExternalHttpUrl string `json:"externalHttpUrl,omitempty"`
AvgDuration float32 `json:"avgDuration,omitempty"`
NumCalls int `json:"numCalls,omitempty"`
CallRate float32 `json:"callRate,omitempty"`
}
type UsageItem struct {
Time string `json:"time,omitempty"`
Timestamp int64 `json:"timestamp"`
@ -207,6 +216,115 @@ func GetUsage(client *SqlClient, query *model.GetUsageParams) (*[]UsageItem, err
return &usageResponse, nil
}
func GetServiceExternalAvgDuration(client *SqlClient, query *model.GetServiceOverviewParams) (*[]ServiceExternalItem, error) {
sqlQuery := fmt.Sprintf(`SELECT TIME_FLOOR(__time, '%s') as "time", AVG(DurationNano) as "avgDuration" FROM %s WHERE ServiceName='%s' AND Kind='3' AND ExternalHttpUrl != '' AND "__time" >= '%s' AND "__time" <= '%s'
GROUP BY TIME_FLOOR(__time, '%s'), ExternalHttpUrl`, query.Period, constants.DruidDatasource, query.ServiceName, query.StartTime, query.EndTime, query.Period)
// zap.S().Debug(sqlQuery)
response, err := client.Query(sqlQuery, "object")
if err != nil {
zap.S().Error(query, err)
return nil, fmt.Errorf("Something went wrong in druid query")
}
// responseStr := string(response)
// zap.S().Info(responseStr)
res := new([]ServiceExternalItem)
err = json.Unmarshal(response, res)
if err != nil {
zap.S().Error(err)
return nil, fmt.Errorf("Error in unmarshalling response from druid")
}
for i, _ := range *res {
timeObj, _ := time.Parse(time.RFC3339Nano, (*res)[i].Time)
(*res)[i].Timestamp = int64(timeObj.UnixNano())
(*res)[i].Time = ""
(*res)[i].CallRate = float32((*res)[i].NumCalls) / float32(query.StepSeconds)
}
servicesExternalResponse := (*res)[1:]
return &servicesExternalResponse, nil
}
func GetServiceExternalErrors(client *SqlClient, query *model.GetServiceOverviewParams) (*[]ServiceExternalItem, error) {
sqlQuery := fmt.Sprintf(`SELECT TIME_FLOOR(__time, '%s') as "time", COUNT(SpanId) as "numCalls", ExternalHttpUrl as externalHttpUrl FROM %s WHERE ServiceName='%s' AND Kind='3' AND ExternalHttpUrl != '' AND StatusCode >= 500 AND "__time" >= '%s' AND "__time" <= '%s'
GROUP BY TIME_FLOOR(__time, '%s'), ExternalHttpUrl`, query.Period, constants.DruidDatasource, query.ServiceName, query.StartTime, query.EndTime, query.Period)
// zap.S().Debug(sqlQuery)
response, err := client.Query(sqlQuery, "object")
if err != nil {
zap.S().Error(query, err)
return nil, fmt.Errorf("Something went wrong in druid query")
}
// responseStr := string(response)
// zap.S().Info(responseStr)
res := new([]ServiceExternalItem)
err = json.Unmarshal(response, res)
if err != nil {
zap.S().Error(err)
return nil, fmt.Errorf("Error in unmarshalling response from druid")
}
for i, _ := range *res {
timeObj, _ := time.Parse(time.RFC3339Nano, (*res)[i].Time)
(*res)[i].Timestamp = int64(timeObj.UnixNano())
(*res)[i].Time = ""
(*res)[i].CallRate = float32((*res)[i].NumCalls) / float32(query.StepSeconds)
}
servicesExternalResponse := (*res)[1:]
return &servicesExternalResponse, nil
}
func GetServiceExternal(client *SqlClient, query *model.GetServiceOverviewParams) (*[]ServiceExternalItem, error) {
sqlQuery := fmt.Sprintf(`SELECT TIME_FLOOR(__time, '%s') as "time", AVG(DurationNano) as "avgDuration", COUNT(SpanId) as "numCalls", ExternalHttpUrl as externalHttpUrl FROM %s WHERE ServiceName='%s' AND Kind='3' AND ExternalHttpUrl != ''
AND "__time" >= '%s' AND "__time" <= '%s'
GROUP BY TIME_FLOOR(__time, '%s'), ExternalHttpUrl`, query.Period, constants.DruidDatasource, query.ServiceName, query.StartTime, query.EndTime, query.Period)
// zap.S().Debug(sqlQuery)
response, err := client.Query(sqlQuery, "object")
if err != nil {
zap.S().Error(query, err)
return nil, fmt.Errorf("Something went wrong in druid query")
}
// responseStr := string(response)
// zap.S().Info(responseStr)
res := new([]ServiceExternalItem)
err = json.Unmarshal(response, res)
if err != nil {
zap.S().Error(err)
return nil, fmt.Errorf("Error in unmarshalling response from druid")
}
for i, _ := range *res {
timeObj, _ := time.Parse(time.RFC3339Nano, (*res)[i].Time)
(*res)[i].Timestamp = int64(timeObj.UnixNano())
(*res)[i].Time = ""
(*res)[i].CallRate = float32((*res)[i].NumCalls) / float32(query.StepSeconds)
}
servicesExternalResponse := (*res)[1:]
return &servicesExternalResponse, nil
}
func GetServiceOverview(client *SqlClient, query *model.GetServiceOverviewParams) (*[]ServiceOverviewItem, error) {
sqlQuery := fmt.Sprintf(`SELECT TIME_FLOOR(__time, '%s') as "time", APPROX_QUANTILE_DS("QuantileDuration", 0.5) as p50, APPROX_QUANTILE_DS("QuantileDuration", 0.9) as p90,