internal/beater/request/result.go (119 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package request
import (
"net/http"
"github.com/pkg/errors"
)
const (
// IDUnset identifies requests not covered by other IDs
IDUnset ResultID = "unset"
// IDRequestCount identifies all requests
IDRequestCount ResultID = "request.count"
// IDResponseCount identifies all responses
IDResponseCount ResultID = "response.count"
// IDResponseErrorsCount identifies all non successful responses
IDResponseErrorsCount ResultID = "response.errors.count"
// IDResponseValidCount identifies all successful responses
IDResponseValidCount ResultID = "response.valid.count"
// IDEventReceivedCount identifies amount of received events
IDEventReceivedCount ResultID = "event.received.count"
// IDEventDroppedCount identifies amount of dropped events
IDEventDroppedCount ResultID = "event.dropped.count"
// IDResponseValidNotModified identifies all successful responses without a modified body
IDResponseValidNotModified ResultID = "response.valid.notmodified"
// IDResponseValidOK identifies responses with status code 200
IDResponseValidOK ResultID = "response.valid.ok"
// IDResponseValidAccepted identifies responses with status code 202
IDResponseValidAccepted ResultID = "response.valid.accepted"
// IDResponseErrorsForbidden identifies responses for forbidden requests
IDResponseErrorsForbidden ResultID = "response.errors.forbidden"
// IDResponseErrorsUnauthorized identifies responses for unauthorized requests
IDResponseErrorsUnauthorized ResultID = "response.errors.unauthorized"
// IDResponseErrorsNotFound identifies responses where route was not found
IDResponseErrorsNotFound ResultID = "response.errors.notfound"
// IDResponseErrorsInvalidQuery identifies responses with invalid query sent
IDResponseErrorsInvalidQuery ResultID = "response.errors.invalidquery"
// IDResponseErrorsRequestTooLarge identifies responses for too large requests
IDResponseErrorsRequestTooLarge ResultID = "response.errors.toolarge"
// IDResponseErrorsDecode identifies responses for requests that could not be decoded
IDResponseErrorsDecode ResultID = "response.errors.decode"
// IDResponseErrorsValidate identifies responses for invalid requests
IDResponseErrorsValidate ResultID = "response.errors.validate"
// IDResponseErrorsRateLimit identifies responses for rate limited requests
IDResponseErrorsRateLimit ResultID = "response.errors.ratelimit"
// IDResponseErrorsTimeout identifies responses for timed out requests
IDResponseErrorsTimeout ResultID = "response.errors.timeout"
// IDResponseErrorsMethodNotAllowed identifies responses for requests using a forbidden method
IDResponseErrorsMethodNotAllowed ResultID = "response.errors.method"
// IDResponseErrorsFullQueue identifies responses when internal queue was full
IDResponseErrorsFullQueue ResultID = "response.errors.queue"
// IDResponseErrorsShuttingDown identifies responses requests occuring after channel was closed
IDResponseErrorsShuttingDown ResultID = "response.errors.closed"
// IDResponseErrorsServiceUnavailable identifies responses where service was unavailable
IDResponseErrorsServiceUnavailable ResultID = "response.errors.unavailable"
// IDResponseErrorsInternal identifies responses where internal errors occured
IDResponseErrorsInternal ResultID = "response.errors.internal"
)
var (
// MapResultIDToStatus takes a ResultID and maps it to a status
MapResultIDToStatus = map[ResultID]Status{
IDResponseValidOK: {Code: http.StatusOK, Keyword: "request ok"},
IDResponseValidAccepted: {Code: http.StatusAccepted, Keyword: "request accepted"},
IDResponseValidNotModified: {Code: http.StatusNotModified, Keyword: "not modified"},
IDResponseErrorsForbidden: {Code: http.StatusForbidden, Keyword: "forbidden request"},
IDResponseErrorsUnauthorized: {Code: http.StatusUnauthorized, Keyword: "unauthorized"},
IDResponseErrorsNotFound: {Code: http.StatusNotFound, Keyword: "404 page not found"},
IDResponseErrorsRequestTooLarge: {Code: http.StatusRequestEntityTooLarge, Keyword: "request body too large"},
IDResponseErrorsInvalidQuery: {Code: http.StatusBadRequest, Keyword: "invalid query"},
IDResponseErrorsDecode: {Code: http.StatusBadRequest, Keyword: "data decoding error"},
IDResponseErrorsValidate: {Code: http.StatusBadRequest, Keyword: "data validation error"},
IDResponseErrorsMethodNotAllowed: {Code: http.StatusMethodNotAllowed, Keyword: "method not supported"},
IDResponseErrorsRateLimit: {Code: http.StatusTooManyRequests, Keyword: "too many requests"},
IDResponseErrorsTimeout: {Code: http.StatusServiceUnavailable, Keyword: "request timed out"},
IDResponseErrorsFullQueue: {Code: http.StatusServiceUnavailable, Keyword: "queue is full"},
IDResponseErrorsShuttingDown: {Code: http.StatusServiceUnavailable, Keyword: "server is shutting down"},
IDResponseErrorsServiceUnavailable: {Code: http.StatusServiceUnavailable, Keyword: "service unavailable"},
IDResponseErrorsInternal: {Code: http.StatusInternalServerError, Keyword: "internal error"},
}
)
// ResultID unique string identifying a requests Result
type ResultID string
// Status holds statuscode and keyword information
type Status struct {
Code int
Keyword string
}
// Result holds information about a processed request
type Result struct {
ID ResultID
StatusCode int
Keyword string
Body interface{}
Err error
Stacktrace string
}
// Reset sets result to it's empty values
func (r *Result) Reset() {
r.ID = IDUnset
r.StatusCode = http.StatusOK
r.Keyword = ""
r.Body = nil
r.Err = nil
r.Stacktrace = ""
}
// Failure returns a bool indicating whether it is describing a successful result or not
func (r *Result) Failure() bool {
return r.StatusCode >= http.StatusBadRequest
}
// SetDefault derives information about the result solely from the ID.
func (r *Result) SetDefault(id ResultID) {
r.set(id, nil, nil)
}
// SetWithError derives information about the result from the given ID and the error.
// The body is derived from the error in case the result describes a failure.
func (r *Result) SetWithError(id ResultID, err error) {
r.set(id, nil, err)
}
// SetWithBody derives information about the result from the given ID. The body is set to the passed value.
func (r *Result) SetWithBody(id ResultID, body interface{}) {
r.set(id, body, nil)
}
// Set allows for the most flexibility in setting a result's properties.
// The error and body information are derived from the given parameters.
func (r *Result) Set(id ResultID, statusCode int, keyword string, body interface{}, err error) {
if r == nil {
return
}
r.ID = id
r.StatusCode = statusCode
r.Keyword = keyword
r.Body = body
r.Err = err
if r.Failure() {
if err == nil {
r.Err = errors.New(keyword)
}
if r.Body == nil {
r.Body = r.Err.Error()
}
}
}
func (r *Result) set(id ResultID, body interface{}, err error) {
if r == nil {
return
}
var statusCode int
var keyword string
if status, ok := MapResultIDToStatus[id]; ok {
statusCode = status.Code
keyword = status.Keyword
} else {
statusCode = MapResultIDToStatus[IDResponseErrorsInternal].Code
keyword = MapResultIDToStatus[IDResponseErrorsInternal].Keyword
}
err = errors.Wrap(err, keyword)
r.Set(id, statusCode, keyword, body, err)
}